GOF23(java设计模式)--创建型模式

单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式

一、单例模式
作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
五种写法:饿汉模式、懒汉模式、双重检测锁、静态内部类实现延迟加载、枚举类实现单例(不细讲了,具体参考我的另一篇文章https://www.jianshu.com/p/e86833bee429
二、简单工厂模式
2.1、作用:用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码)
2.2、缺点:对于增加新产品无能为力!不修改代码的话,是无法扩展的,不完全满足开闭原则(如下面的例子,如果再增加华为电脑,则必须修改工厂类的代码)
2.3、UML图:

简单工厂模式.png

2.4、示例:

//电脑接口
public interface Computer {
    public void play();
}
//联想电脑类
class LenovoComputer implements Computer{
    public void play() {
        System.out.println("我是联想电脑");
    }
}
//苹果电脑类
class MacComputer implements Computer{
    public void play() {
        System.out.println("我是苹果电脑");
    }
}
--------------------------------------------------------------------------------
//简单工厂类,类方法一般为静态的,所以也称为静态工厂
public class SimpleFactory {
    public static Computer createComputer(String type){
        if(type.equalsIgnoreCase("mac")){
            return new MacComputer();
        }else{
            return new LenovoComputer();
        }
    }
    
    public static Computer createLenovoComputer(){
        return new LenovoComputer();
    }
    
    public static Computer createMacComputer(){
        return new MacComputer();
    }
}
--------------------------------------------------------------------------------
//客户端
public class Client {
    public static void main(String[] args) {
        SimpleFactory simpleFactory = new SimpleFactory();
        Computer c1 = simpleFactory.createComputer("mac");
        Computer c2 = simpleFactory.createLenovoComputer();
        c1.play();
        c2.play();
    }
}

三、工厂方法模式
3.1、作用:为了避免简单工厂模式的缺点,不完全满足开闭原则,而设计的。工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类
3.2、缺点:除了是满足开闭原则外,从结构复杂度、代码复杂的、客户端编程难度、管理上的难度上看,工厂方法相比简单工厂都要复杂,所以实际上,我们一般只会用简单工厂,很少会用到工厂方法模式
3.3、UML图:


工厂方法模式.png

3.4、示例:

//电脑接口
public interface Computer {
    public void play();
}
//联想电脑类
class LenovoComputer implements Computer{
    public void play() {
        System.out.println("我是联想电脑");
    }
}
//苹果电脑类
class MacComputer implements Computer{
    public void play() {
        System.out.println("我是苹果电脑");
    }
}
--------------------------------------------------------------------------------
//工厂接口
public interface FactoryMethod {
    public Computer createComputer();
}
//联想工厂
class LenovoComputerFactory implements FactoryMethod{
    public Computer createComputer() {
        return new LenovoComputer();
    }
}
//苹果工厂
class MacComputerFactory implements FactoryMethod{
    public Computer createComputer() {
        return new MacComputer();
    }
}
--------------------------------------------------------------------------------
//客户端
public class Client {
    public static void main(String[] args) {
        FactoryMethod factory1  = new LenovoComputerFactory();
        FactoryMethod factory2  = new MacComputerFactory();
        LenovoComputer c1 = (LenovoComputer) factory1.createComputer();
        MacComputer c2 = (MacComputer) factory2.createComputer();
        c1.play();
        c2.play();
    }
}

结论:由此看出,如果再加入一个华为的电脑,只需加入一个华为电脑的类和一个华为电脑工厂就可以了,不需要修改之前的任何代码,因此满足了开闭原则

四、抽象工厂模式
4.1、作用:用来生产不同产品族的全部产品,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
4.2、缺点:对于增加新的产品,无能为力;支持增加产品族(如在下面例子中,若再加入华为电脑,则需要新增华为电脑工厂类,并要修改每一个配件类,去新增产品配件,因此就不能满足开闭原则了)
4.3、UML图:


抽象工厂模式.png

4.4、示例:

//电脑类
public class Computer {
    private Engine engine;
    private Keyboard keyboard;
    private Mouse mouse;
    public Engine getEngine() {
        return engine;
    }
    public void setEngine(Engine engine) {
        this.engine = engine;
    }
    public Keyboard getKeyboard() {
        return keyboard;
    }
    public void setKeyboard(Keyboard keyboard) {
        this.keyboard = keyboard;
    }
    public Mouse getMouse() {
        return mouse;
    }
    public void setMouse(Mouse mouse) {
        this.mouse = mouse;
    }
    public void play(){
        System.out.println(engine.getName()+keyboard.getName()+mouse.getName());
    };
}
//引擎类(为了简洁,此处没有用到接口,直接用名字代表不同的对象)
class Engine{
    private String name;
    public Engine(String name){this.name=name;}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//键盘类(为了简洁,此处没有用到接口,直接用名字代表不同的对象)
class Keyboard{
    private String name;
    public Keyboard(String name){this.name=name;}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//鼠标类(为了简洁,此处没有用到接口,直接用名字代表不同的对象)
class Mouse{
    private String name;
    public Mouse(String name){this.name=name;}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
--------------------------------------------------------------------------------
//抽象工厂接口
public interface AbstractFactory {
    public Computer createComputer();
}
//联想电脑工厂
class LenovoComputerFactory implements AbstractFactory{
    public Computer createComputer() {
        Computer c = new Computer();
        c.setEngine(new Engine("联想CPU"));
        c.setKeyboard(new Keyboard("联想键盘"));
        c.setMouse(new Mouse("联想鼠标"));
        return c;
    }
}
//苹果电脑工厂
class MacComputerFactory implements AbstractFactory{
    public Computer createComputer() {
        Computer c = new Computer();
        c.setEngine(new Engine("苹果CPU"));
        c.setKeyboard(new Keyboard("苹果键盘"));
        c.setMouse(new Mouse("苹果鼠标"));
        return c;
    }
}
--------------------------------------------------------------------------------
//客户端
public class Client {
    public static void main(String[] args) {
        AbstractFactory Lenovofactory = new LenovoComputerFactory();
        AbstractFactory Macfactory = new MacComputerFactory();
        Computer LenovoComputer = Lenovofactory.createComputer();
        Computer MacComputer = Macfactory.createComputer();
        LenovoComputer.play();
        MacComputer.play();
    }
}

五、建造者模式
5.1、作用:分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况下使用。由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
5.2、UML图:


建造者模式.png

5.3、示例:

//电脑类
public class Computer {
    private Engine engine;
    private Keyboard keyboard;
    private Mouse mouse;
    public Engine getEngine() {
        return engine;
    }
    public void setEngine(Engine engine) {
        this.engine = engine;
    }
    public Keyboard getKeyboard() {
        return keyboard;
    }
    public void setKeyboard(Keyboard keyboard) {
        this.keyboard = keyboard;
    }
    public Mouse getMouse() {
        return mouse;
    }
    public void setMouse(Mouse mouse) {
        this.mouse = mouse;
    }
    public void play(){
        System.out.println(engine.getName()+keyboard.getName()+mouse.getName());
    };
}
//引擎类
class Engine{
    private String name;
    public Engine(String name){this.name=name;}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//键盘类
class Keyboard{
    private String name;
    public Keyboard(String name){this.name=name;}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//鼠标类
class Mouse{
    private String name;
    public Mouse(String name){this.name=name;}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
--------------------------------------------------------------------------------
//电脑构建接口
public interface ComputerBuilder {
    public Engine createEngine();
    public Keyboard createKeyBoard();
    public Mouse createMouse();
}
class realComputerBuilder implements ComputerBuilder{
    public Engine createEngine() {
        return new Engine("联想CPU");
    }
    public Keyboard createKeyBoard() {
        return new Keyboard("苹果键盘");
    }
    public Mouse createMouse() {
        return new Mouse("华为鼠标");
    }
}
--------------------------------------------------------------------------------
//电脑组装接口
public interface ComputerDirector {
    public Computer computerDirector(ComputerBuilder computerBuilder);
}
class realComputerDirector implements ComputerDirector{
    public Computer computerDirector(ComputerBuilder computerBuilder) {
        Computer c = new Computer();
        c.setEngine(computerBuilder.createEngine());
        c.setKeyboard(computerBuilder.createKeyBoard());
        c.setMouse(computerBuilder.createMouse());
        return c;
    }
}
--------------------------------------------------------------------------------
//客户端
public class Client {
    public static void main(String[] args) {
        ComputerBuilder computerBuilder = new realComputerBuilder();
        ComputerDirector computerDirector = new realComputerDirector(); 
        Computer c =computerDirector.computerDirector(computerBuilder);
        System.out.println(c.getEngine().getName()+""+c.getKeyboard().getName()+""+c.getMouse().getName()+"");
    }
}
--------------------------------------------------------------------------------
总结:如上代码,如果要生产不同型号的配件,只需要创建一个新的构造器类,需要组装成不同型号的电脑也只需要创建一个新的组黄器类,不需要修改之前的代码

六、原型模式(prototype)
6.1、作用:通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。它本身就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点。优势有:效率高(直接克隆,避免了重新执行构造过程步骤) 。克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值。克隆出的对象的属性值完全和原型对象相同。并且克隆出的新对象改变不会影响原型对象。然后,再修改克隆对象的值。
6.2、重要知识点:克隆问题(浅克隆和深克隆,此处不详说,请另行查看我的文章:https://www.jianshu.com/p/d2783a7cf031
6.3、UML图:

原型模式.png

6.4、示例:

//电脑类
public class Computer implements Serializable{
    private Engine engine;
    private Keyboard keyboard;
    private Mouse mouse;
    public Engine getEngine() {
        return engine;
    }
    public void setEngine(Engine engine) {
        this.engine = engine;
    }
    public Keyboard getKeyboard() {
        return keyboard;
    }
    public void setKeyboard(Keyboard keyboard) {
        this.keyboard = keyboard;
    }
    public Mouse getMouse() {
        return mouse;
    }
    public void setMouse(Mouse mouse) {
        this.mouse = mouse;
    }
    public void play(){
        System.out.println(engine.getName()+keyboard.getName()+mouse.getName());
    };
}
//引擎类
class Engine implements Serializable{
    private String name;
    public Engine(String name){this.name=name;}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//键盘类
class Keyboard implements Serializable{
    private String name;
    public Keyboard(String name){this.name=name;}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//鼠标类
class Mouse implements Serializable{
    private String name;
    public Mouse(String name){this.name=name;}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
--------------------------------------------------------------------------------
public class ComputerClone {
    public Computer clone(Computer c){
        Computer c2 =null;
        try {
            ByteArrayOutputStream bas =new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bas);
            oos.writeObject(c);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bas.toByteArray()));
            c2 =(Computer) ois.readObject();
            bas.flush();oos.flush();
            bas.close();oos.close();
            ois.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return c2;
    }
}
--------------------------------------------------------------------------------
public class Client {
    public static void main(String[] args) {
        ComputerClone computerClone = new ComputerClone();
        Computer c = new Computer();
        c.setEngine(new Engine("华为CPU"));
        c.setKeyboard(new Keyboard("联想键盘"));
        c.setMouse(new Mouse("苹果鼠标"));
        Computer c2 = computerClone.clone(c);
        System.out.println(c);
        System.out.println(c2);
        System.out.println(c2.getEngine().getName()+""+c2.getKeyboard().getName()+""+c2.getMouse().getName()+"");
    }
}
--------------------------------------------------------------------------------
结果:
com.primeton.GOF23.prototype.Computer@6727734f
com.primeton.GOF23.prototype.Computer@7176c74b
华为CPU联想键盘苹果鼠标
--------------------------------------------------------------------------------
总结:通过结果可以看到克隆出来的对象是一个新对象,但其中属性与原型对象一致,整个新对象产生的过程很简单,效率高(直接克隆,避免了重新执行构造过程步骤) 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容

  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,740评论 0 14
  • UML概述 UML简介 UML (Unified Modeling Language)为面向对象软件设计提供统一的...
    aron1992阅读 515评论 0 0
  • 字节跳动飞书内推!北京、杭州、武汉、广州、深圳、上海,六大城市等你来投。感兴趣的朋友可以私我咨询&内推,也可以通过...
    卢卡斯哔哔哔阅读 610评论 0 3
  • 伸手党一般都爱到处问人要健身计划,基本被问得人心里都是拒绝的。原因是没见过不了解你的体型和身体状况。在这种情况下贸...
    九月艺文阅读 965评论 0 0
  • 从前我有远大理想,想做一个伟大的人,造福人类,万中挑一。 可真是个单纯天真的年纪啊,那时的我眼见小,目光所及不过生...
    林星海阅读 1,044评论 2 4