2018-02-26-设计模式-工厂模式

除了使用new操作符之外,还有更多制造对象的方法。你讲了解到实例化这个活动不应该总是公开的进行,也会认识到初始化经常造成“耦合”问题。你将了解工厂模式如何从复杂的依赖中帮你脱困。
当看到new,就会想到具体 所以用的的确是实现,而不是接口。

new 有什么不对劲?

在技术上,new没有错,毕竟这是java的基础部分。真正的犯人是我们的老朋友“改变”,以及踏实如何影响new的使用的。

针对接口编程,可以隔离掉以后系统可能发生的一大堆改变,为什么呢?如果代码是针对接口而写,那么通过多态,他可以与任何新类 实现该接口。但是,当代码使用大量的具体类时,等于是自找麻烦,因为一旦加入新的具体类,就必须改变代码。也就是说你的代码并非“对修改关闭”。想用新的具体类型来扩展代码,必须重新打开它。
记住,这个设计应该 对扩展开放对修改关闭

如何将实例化具体类的代码从应用中抽离,或者封装起来,使它们不会干扰应用的其他部分?

识别变化的方面

披萨店

Pizza orderPizza(){
//为了让系统有弹性,我们希望这是一个抽象类或接口。但如果这样,这些类或接口就无法直接实例化。
    Pizza pizza = new Pizza();
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    return pizza;
}

但是你需要更多披萨类型……
所以必须增加一些代码,来决定适合的披萨类型,然后再“制造”这个披萨。

Pizza orderPizza(String type){
        Pizza pizza ;
        if(type.equals("cheese")){
               pizza=new CheesePizza();
        }else if(type.equals("greek")){
               pizza=new GreekPizza();
        }else if(type.equals("pepperoni")){
               pizza=new PepperoniPizza();
        }
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

但是压力来自于增加更多的披萨类型
你发现其他餐厅又多了很多流行风味的披萨:ClamPizza(蛤蜊披萨)、VeggiePizza(素食披萨)。很明显你要赶上他们,需要把这些加入你的菜单中,而最近GreekPizza(希腊披萨)卖的不好,所以你决定将它从菜单中去掉:

Pizza orderPizza(String type) {
    Pizza pizza;
    //这是变化的部分。随着时间过去比萨菜单改变,这里就必须一改再改。
    if (type.equals("cheese")) {
        pizza = new CheesePizza();
    }
    //此代码没有对修改封闭。如果比萨店改变他所供应的比萨风味,就得进到这里来修改。
    /*else if (type.equals("greek")) {
        pizza = new GreekPizza();
    } */else if (type.equals("pepperoni")) {
        pizza = new PepperoniPizza();
    } else if (type.equals("clam")) {
        pizza = new ClamPizza();
    } else if (type.equals("veggie")) {
        pizza = new VeggiePizza();
    }
    //这里是我们不想改变的地方。因为比萨的准备,烘烤,包装,多年都持续不变,所以这部分的代码不会改变,只是发生这些动作的比萨会改变。
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    return pizza;
}

很明显,如果实例化“某些”具体类,将使orderPizza()出问题,而且也无法让orderPizza()对修改关闭,但是,现在我们已经知道哪些会改变,哪些不会改变,该是使用封装的时候了。

封装创建对象的代码

我们称这个新对象为“工厂”。
工厂处理创建对象的细节。一旦有了SimplePizzaFactory,orderPizza()就变成此对象的客户。当需要比萨时,就叫比萨工程做一个。那些orderPizza()方法需要知道希腊比萨和蛤蜊比萨的日子不去不复返了。现在orderPizza()方法只关心从工厂得到了一个比萨,而这个比萨实现了Pizza接口,所以它可以调用prepare()、bake()、cut()、box()来分别进行准备、烘烤、切片、装盒。
建立一个简单披萨工厂

//SimplePizzaFactory是新的类,他只做一件事情:帮它的客户创建比萨
public class SimplePizzaFactory {
    //首先,在这个工厂内定义一个createPizza()方法,所有客户用这个方法来实例化对象。
    public Pizza createPizza(String type) {
        Pizza pizza = null;

        if ("cheese".equals(type)) {

        } else if ("pepperoni".equals(type)) {

        } else if ("clam".equals(type)) {

        } else if ("veggie".equals(type)) {

        }
        return pizza;
    }
}

重做PizzaStore类
修改我们的客户代码,我们要做的是仰仗工厂来为我们创建披萨。

public class PizzaStore {
    //为PizzaStore加上一个对SimplePizzaFactory的引用
    SimplePizzaFactory factory;
    //PizzaStore的构造器,需要一个工厂作为参数。
    public PizzaStore(SimplePizzaFactory factory) {
        this.factory = factory;
    }
    public Pizza orderPizza(String type) {
        Pizza pizza;
        //把new操作符替换成工厂对象的创建方法。这里不再使用具体实例化!
        pizza = factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

定义简单工厂
简单工厂其实不是一个设计模式,反而比较像是一种编程习惯,但由于进场被使用。所以任务是工厂模式。
我们来看看新的披萨店类图:


image.png

再次提醒:在设计模式中,所谓的“实现一个接口”并“不一定”表示“写一个类,并利用implement关键词来实现某个java接口”。“实现一个接口”泛指“实现某个超级类型(可以使类或接口)的某个方法

加盟披萨店

你的披萨店经营有成,击败了竞争者,现在大家都希望比萨店能在自己家附加有加盟店。每家加盟店都可能想要提供不同风味的披萨(纽约,芝加哥,加州)。

我们已经有一个做法……

如果利用SimplePizzaFactory,写出三种不同的工厂,分别是
NYPizzaFactory,ChicagoPizzaFactory,CaliforniaPizzaFactory,各地加盟店都有适合的工厂可以使用,这是一种做法。

NYPizzaFactory nyFactory=new NYPizzaFactory();
PizzaStore nyStore=new PizzaStore(nyFactory);
nyFactory.orderPizza("Veggie");

但是你想要多一些质量控制……
你发现加盟店确实采用你的工厂创建披萨,但是其他部分,却开始采用他们自创的流程:烘烤的做法有些差异,不要切片,使用其他厂商的盒子。
在我们稍早的SimplePizzaFactory代码之前,制作披萨的代码绑在PizzaStore里,但是这么做却没有弹性,那么,该怎么办。

给披萨店使用的框架

有个做法可让披萨制作局限于PizzaStore类,而同时又能让这些加盟店依然可以自由地制作该区域的风味。
所要做的事情,就是把createPizza()方法放回到PizzaStore中,不过要把它设置成“抽象方法”,然后为每个区域风味创建一个PizzaStore的子类。

public abstract class PizzaStore {
    
    public Pizza orderPizza(String type) {
        Pizza pizza;
        //现在createPizza()方法从工厂对象中移回PizzaStore
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

    //在PizzaStore里,“工厂方法”现在是抽象的。
    abstract Pizza createPizza(String type);
}

现在已近有一个PizzaStore作为超类,让每个域类型(NYPizzaFactory,ChicagoPizzaFactory,CaliforniaPizzaFactory)都继承这个PizzaStore,每个子类各自决定如何制造披萨,

允许子类做决定

别忘了,PizzaStore已经有一个不错的订单系统,由orderPizza()方法负责处理订单,我们现在要让createPizza()能够应对这些变化来负责创建正确种类的披萨,做法是让PizzaStore的各个子类负责定义自己的createPizza()方法,所以我们会得到一些PizzaStore具体的子类,每个子类都有自己的披萨变体,而任然适合PizzaStore框架,并使用调试好的orderPizza()方法。


image.png
让我们开家比萨店吧

纽约风味店:

//NyPizzaStore扩展自PizzaStore,所以拥有orderPizza()方法(以及其他方法)。
public class NyPizzaStore extends PizzaStore {
    //createPizza()返回一个Pizza对象,由子类全权负责该实例化哪个具体Pizza
    //必须实现createPizza()方法,因为在PizzaStore里他是抽象的。
    @Override
    Pizza createPizza(String type) {
        Pizza pizza = null;
        if ("cheese".equals(type)) {

        } else if ("pepperoni".equals(type)) {

        } else if ("clam".equals(type)) {

        } else if ("veggie".equals(type)) {

        }
        return pizza;
    }
}

披萨类:

public class Pizza {
    String name;
    String dough;
    String sauce;
    ArrayList toppings = new ArrayList();

    public void prepare() {
        System.out.println("Preparing " + name);
        System.out.println("Tossing dough...");
        System.out.println("Addubg sauce...");
        System.out.println("Addubg toppings...");
        for (int i = 0; i < toppings.size(); i++) {
            System.out.println("  " + toppings.get(i));
        }

    }

    public void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }

    public void cut() {
        System.out.println("Cuting the pizza into diagonal slices");
    }

    public void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    public String getName() {
        return name;
    }
}

我们需要一些具体子类,来定义纽约和芝加哥风味的芝士披萨。


public class NYStyleCheesePizza extends Pizza {

    public NYStyleCheesePizza() {
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
        toppings.add("Grated Reggiano Cheese");
    }
}

public class ChicagoStyleCheesePizza extends Pizza {
    public ChicagoStyleCheesePizza() {
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";
        toppings.add("Shredded Mozzarella Cheese");
    }

    @Override
    public void cut() {
        //这里覆盖了cut()方法 将比萨切成正方形
        System.out.println("Cutting the pizza into square slices");
    }
}

你已经等得够久了,来吃些披萨吧

       PizzaStore pizzaStore = new NyPizzaStore();
       Pizza pizza = pizzaStore.orderPizza("cheese");
       System.out.println("Ethan ordered a"+pizza.getName()+"\n");
认识工厂方法模式的时候终于到了

所有工厂模式都用来封装对象的创建。工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。看看类图:


创建者.png

产品.png
另一个观点:平行的类层级
image.png
定义工厂方法模式

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类吧实例化推迟到子类。

工厂模式类图


工厂模式类图

工厂方法模式能够封装具体类型的实例化,抽象的Creator提供了一个创建对象的方法的接口,在抽象的Creator中,任何其他实现的方法,都可能使用到这个工厂方法所制造出来的产品,但只有子类真正实现这个工厂方法并创建产品。
看看对象依赖
当你直接实例化一个对象时,就是在依赖它的具体类,返回前页看看这个依赖性很高的比萨店例子,它由披萨店类来创建所有的披萨对象,而不是委托给工厂。

设计原则

依赖倒置原则 要依赖抽象,不要依赖具体类。

首先,这个原则听起来很像是“针对接口编程,不针对实现编程”,不是吗?的确很相似,然而这里更强调“抽象”。这个原则说明了:不能让高层组件依赖底层组件,而且,不管高层或底层组件,两者都应该依赖抽象。

让我们看前面,PizzaStore是“高层组件”,而披萨实现是“底层组件”很清楚地,PizzaStore依赖这些具体披萨类。

现在这个原则告诉我们,应该重写代码以便于我们依赖抽象类,而不依赖具体类。对于高层及底层模块都应该如此。

依赖倒置原则,究竟倒置在哪里?
在依赖倒置原则中的倒置指的是和一般OO设计的思考方式完全相反。
你会注意到前面的底层主键现在竟然依赖高层的抽象。同样的,高层组件现在也依赖相同的抽象。

倒置你的思考方式

1、好的,所以你需要试下一个比萨店,你第一件想到的事情是什么?
嗯!比萨店进行准备、烘烤、装盒、所以我的店必须能制作许多不同风味的比萨,例如:芝士比萨、素食比萨、蛤蜊比萨。。。
2、没错!先从顶端开始,然后往下倒具体类。但是,正如你所看到的你不想让比萨理会这些具体类,要不然比萨店将全都依赖这些具体类。现在 倒置 你的想法 、、、 别从顶端开始,而是从比萨Pizza 开始,然后想想看能抽象化些什么?
是的 芝士比萨、素食比萨、蛤蜊比萨都是比萨,所以应该共享一个Pizza接口。

对了 你想要抽象化一个Pizza。

3、很接近了,但是要这么做,必须靠一个工厂来经这些具体类取出比萨店。一旦你这么做了,各种不同的具体比萨类型就只能依赖一个抽象,二比萨店也会一来这个抽象。我们已经倒置了一个商店依赖具体类的设计,而且也倒置了你的思考方式。
既然我已经有一个比萨抽象,就可以开始设计比萨店,而不用理会具体的比萨类了。

下面的指导方针,能避免在OO设计中违反依赖倒置原则:

1、变量不可以持有具体类的引用。
如果使用new,就会持有具体类的引用,你可以改用工厂来避开这样的做法。
2、不要让类派生自具体类。
如果派生自具体类,你就会以来具体类。请派生自一个抽象(接口或抽象类)。
3、不要覆盖基类中已实现的方法。
如果覆盖基类已实现的方法,那么你的基类就不是一个真正适合被继承的抽象。基类中已实现的方法,应该有所有的子类共享。

再回到比萨店

有些家门店使用低价原料来增加利润。必须采取一些手段,确保原料的一致

打算建造一家生产原料的工厂,并将原料运送到各家加盟店。对于这个做法,现在还剩下一个问题。家门店坐落在不同的区域,纽约的红酱料和芝加哥的红酱料是不一样的。所以对于纽约和芝加哥,你准备两组不同的原料。


image.png
建造原料工厂
//这个接口负责创建所有的原料
public interface PizzaIngredientFactory {
    public Dough createDough();

    public Sauce createSauce();

    public Cheese createCheese();

    public Veggies[] createVeggies();

    public Pepperoni createPepperoni();

    public Clams createClam();
    //这里有许多类,每个原料都是一个类
    //在接口中,每个原料都有一个对应的方法创建该原料
    //如果每个工厂实例内部都有某一种通用的机制需要实现,就可以吧这个例子改写成抽象类
}
要做的事情是:

1.为每个区域建造一个工厂,你需要创建一个继承自PizzaIngredientFactory的子类来实现每一个创建方法。
2.实现一组原料类供工厂使用,例如ReggianoCheese,RedPeppers,ThickCrustDough.这些类可以在何时的区域间共享。
3.然后你仍然需要将这一切组织起来,将新的原料工厂整合进旧的PizzaStore代码中。

创建纽约原料工厂
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    @Override
    public Dough createDough() {
        return new ThinCurstDough();
    }

    @Override
    public Sauce createSauce() {
        return new MarinaraSauce();
    }

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }

    @Override
    public Veggies[] createVeggies() {
        Veggies veggies[] = {new Garlic(),
                new Onion(),
                new Mushroom(),
                new RedPepper()};
        return veggies;
    }

    @Override
    public Pepperoni createPepperoni() {
        return new SlicedPepperoni();
    }

    @Override
    public Clams createClam() {
        return new FreshClams();
    }
}
重做比萨。。。

工厂已经一切就绪,准备生产高质量原料了,现在我们只需要重做比萨,好让它们使用工厂生产出来的原料。先从抽象的Pizza类开始:

public abstract class Pizza {
    String name;
    Dough dough;
    Sauce sauce;
    Veggies veggies[];
    Cheese cheese;
    Pepperoni pepperoni;
    Clams clams;
    abstract void prepare();
    void bake() {
        System.out.println("Back for 25 minutes at 350");
    }
    void cut() {
        System.out.println("Cutting the pizza into diagonal slices");
    }
    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }
    public String getName() {
        return name;
    }
    void setName(String name) {
        this.name = name;
    }
    public String printString() {
        //这里打印披萨的代码
        return "";
    }
}
继续重做比萨

现在已经有一个抽象比萨,可以开始创建纽约和芝加哥风味的比萨了 。从今以后家门店必须直接从工厂取得原料。

public class CheesePizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;

    //要制作比萨,需要工厂提供原料。所以每个比萨类都需要从构造器参数中得到一个工厂,并把这个工厂存储在一个实例中
    public CheesePizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }
    @Override
    void prepare() {
        System.out.println("Preparing " + getName());
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
    }
}
    //Pizza的代码利用相关的工厂生产原料。所生产的原料依赖所使用的工厂,
    // Pizza类根本不关心这些原料,他只知道如何制作比萨。
    // 现在,Pizza和区域原料之间被解耦,无论原料工厂是在洛基山脉还是西北沿岸地区,Pizza类都可以轻易地复用完全没问题。
    // sauce = ingredientFactory.createSauce();

    
    //sauce:把pizza的实例变量设置为此比萨所使用的某种酱料
    //ingredientFactory:这是原料工厂,pizza不在乎使用什么工厂,只要是原料工厂就行了。
    //createSauce():方法会返回这个区域所使用的酱料。如果这是一个纽约原料工厂,我们将取得大蒜番茄酱料
再回到比萨店
public class NYPizzaStore extends PizzaStore {
    @Override
    Pizza createPizza(String type) {
        Pizza pizza = null;
        //纽约店会用到纽约比萨原料工厂,由该原料工厂负责生产所有纽约风味比萨所需的原料。
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        if (type.equals("cheese")) {
             //把工厂传递给每一个比萨,以便比萨能从工厂中取得原料。
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("New York Style Cheese PizzaOld");
        } else if (type.equals("veggies")) {
            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("New York Style Veggies PizzaOld");
        } else if (type.equals("clam")) {
            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("New York Style Clam PizzaOld");
        }
        return pizza;

    }
}

一连串的代码改变;我们到底做了些什么?

我们引入新类型的工厂,也就是所谓的抽象工厂,来创建比萨原料家族。
通过抽象工厂所提供的接口,可以创建产品的家族,利用这个接口书写代码,我们的代码将从实际工厂解耦,以便在不同上下文中实现各式各样的工厂,制造出各种不同的产品。例如:不同的区域,不同的操作系统,不同的外观及操作。
因为代码从实际的产品中解耦了,所以我们可以替换不同的工厂来取得不同的行为(例如:取得大蒜番茄酱料,而不是取得番茄酱料)。

定义抽象工厂模式

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么,这样一来,客户就从具体的产品中被解耦。


image.png

这是一张更复杂的类图,让我们从PizzaStore的观点来看一看它:

image.png

原则 依赖倒置原则: 依赖抽象,不要依赖具体类.

抽象工厂模式-----提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

工厂方法模式-----定义了一个创建对象的接口,但由子类决定要实例化的嘞是哪一个。工厂方法让类吧实例化推迟到子类。

要点

  • 所有的工厂都是用来封装对象的创建
  • 简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户长须从具体类解耦
  • 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
  • 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中
  • 所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合
  • 工厂方法允许类将实例化延迟到子类进行。
  • 抽象工厂创建相关的对象家族,而不需要依赖他们的具体类
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,875评论 1 15
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,723评论 3 13
  • 今天学习下最常见的工厂模式,工厂模式细分下来有三大类: 他们的目标都是一样的:封装对象的创建。但是实现手段和使用场...
    西木柚子阅读 2,136评论 7 28
  • 设计原则: 要依赖抽象,不要依赖具体类 目录 本文的结构如下: 什么是工厂方法模式 为什么要用该模式 模式的结构 ...
    w1992wishes阅读 1,314评论 0 6
  • 我喜欢吃葡萄,吃葡萄不吃葡萄皮也不吃葡萄籽。我最爱的是巨峰,个头大,甜度不大但有葡萄的清香。 我家常买的却是玫瑰香...
    苗苗的麻麻阅读 173评论 0 1