上一篇:《设计模式03—装饰者模式》

4.工厂模式

针对接口编程,可以隔离掉以后系统可能发生的一大堆改变。
为什么呢?如果代码是针对接口而写,那么通过多态,它可以与任何新类实现该接口。但是,当代码使用大量的具体类时,等于是自找麻烦,因为一旦加入新的具体类就必须改变代码。
也就是说,你的代码并非关闭”。想用新的具体类型来扩展代码,必须重新打开它。
所以当遇到这样的问题时,该怎么办?,就应该回到OO设计原则去寻找线索。我们的第一个原则用来处理改变,并帮助我们“找出会变化的方面,把它们从不变的部分分离出来”。
针对这个问题我们开始识别变化的方面
假设我们有一个披萨店,我们对于订购披萨的代码可能如下所示:

public Pizza OrderPizza() {Pizza pizza=new Pizza();pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;
}

为了让系统有弹性,我们很希望这是一个抽象类或接口。但是如果这样,这些类或接口就无法直接实例化。
但是我们需要更多的披萨类型,所以必须增加一些代码来决定适合的披萨类型,在进行制造:

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

这种代码在实际使用中,一旦新增或者去掉一种披萨,那么我们的代码就要重写,比如由于芝士披萨卖的不好,我们需要从菜单中去除,所以代码就会以下所示:

public Pizza OrderPizza(String type) {Pizza pizza=new Pizza();if(type.equals("greek")){pizza=new GreekPizza();}pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;
}

但是始终保持不变的还是披萨的prepare,bake,cut,box
所以我们将变化的提取出来,然后把这个变化的部分搬到另外一个对象中,这个新对象只负责如何创建披萨,我们称这个新对象为“工厂”,于是我们的工厂模式就应运而生了,为了后面方便叙述,我们把这个新对象命名为SimplePizzaFactory。
工厂(factory)处理创建对象的细节。一旦有了SimplePizzaFactory ,orderPizza()就变成此对象的客户。当需要比萨时,就叫比萨工厂做一个。那些orderPizza()方法需要知道希腊比萨或者蛤螂比萨的日子一去不复返了。现在orderPizza()方法只关心从工厂得到了一个比萨,而这个比萨实现了Pizza接口,所以它可以调用prepare(),bake(),cut(),box()来分别进行准备、烘烤、切片、装盒。
下面我们先建立一个简单的披萨工厂
先从工厂本身开始。我们要定义一个类,为所有比萨封装创建对象的代码。代码像这样……

/*** 它只做一件事,帮他的客户创建披萨*/
public class SimplePizzaFactory {public Pizza createPizza(String type) {Pizza pizza = null;if (type.equals("cheese")) {pizza = new CheesePizza();} else if (type.equals("pepperoniPizza")) {pizza = new PepperoniPizza();} else if (type.equals("clam")) {pizza = new ClamPizza();} else if (type.equals("veggie")) {pizza = new VeggiePizza();}return pizza;}
}

接下来我们重做PizzaStroe类

public class PizzaStore {SimplePizzaFactory factory;public PizzaStore(SimplePizzaFactory factory) {//构造器,需要一个工厂作为参数this.factory = factory;}public Pizza orderPizza(String type) {Pizza pizza;pizza = factory.createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}
}

定义简单工厂

简单工厂其实不是一个设计模式,反而比较像是种编程习惯
不要因为简单工厂不是一个“真正的”模式,就忽略了它的用法。让我们来看看新的比萨店类图:

注意:在设计模式中,所调的“实现一个接口“不一定”表示“写一个类,并利用implements关键词来实现某个接口,实现接口泛指实现某个超类型(可以是类也可以是接口)的某个方法

加盟披萨店

每家加盟店都可能想要提供不同风味的比萨(比方说纽约、芝加哥、加州),这受到了开店地点及该地区比萨美食家口味的影响。

我们如何去做呢?
首先先看看PizzaStore所做的改变:

public abstract class PizzaStore {public Pizza orderPizza(String type) {Pizza pizza;pizza = createPizza(type);//将创建披萨的方法从工厂中移回pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}abstract Pizza createPizza(String type);//把工厂对象移到这个方法中
}

现在已经有一个PizzaStore作为超类;
让每个域类型(NYPizzaStore,ChicagoPizzaStore、CaliforniaPizzaStore)都继承这个PizzaStore,每个子类各自决定如何制造比萨。

现在,更进一步地,orderPizza()方法对Pizza对象做了许多事情(例如:准备、烘烤、切片、装盒),但由于Pizza对象是抽象的,orderPizza()并不知道哪些实际的具体类参与进来了。换句话说,这就是解耦(decouple)!

当orderPizza()调用createPizza()时,某个比萨店子类将负责创建比萨。
做哪一种比萨呢?
当然是由具体的比萨店来决定
那么,子类是实时做出这样的决定吗?
不是,但从orderPizza()的角度来看,如果选择在NYStylePizzaStore订购比萨,就是由这个子类(NYStylePizzaStore)决定。
严格来说,并非由这个子类实际做“决定”,而是由“顾客”决定到哪一家风味的比萨店才决定了比萨的风味。
于是我们一次看看NYPizzaStore(纽约风味的披萨)长什么样子吧

/*** 纽约风格的披萨商店*/
public class NYPizzaStore extends PizzaStore {@OverridePizza createPizza(String type) {if (type.equals("cheese")) {return new NYStyleCheesePizza();} else if (type.equals("veggie")) {return new NYStyleVeggiePizza();} else if (type.equals("clam")) {return new NYStyleClamPizza();} else if (type.equals("pepperoni")) {return new NYStylePepperoniPizza();}return null;}
}
  • Pizza

      /*** 披萨的基类*/abstract public class Pizza {String name;//披萨的名称String dough;//披萨的所用的面料String sauce;//披萨所用的酱料List<String> toppings = new ArrayList<String>();public String getName() {return name;}//准备披萨public void prepare() {System.out.println("Preparing " + name);}//烘烤披萨public void bake() {System.out.println("Baking " + name);}//裁剪披萨public void cut() {System.out.println("Cutting " + name);}//打包披萨public void box() {System.out.println("Boxing " + name);}public String toString() {// code to display pizza name and ingredientsStringBuffer display = new StringBuffer();display.append("---- " + name + " ----\n");display.append(dough + "\n");display.append(sauce + "\n");for (String topping : toppings) {display.append(topping + "\n");}return display.toString();}}
  • NYStyleCheesePizza
      /*** 纽约风味的芝士披萨*/public class NYStyleCheesePizza extends Pizza {public NYStyleCheesePizza() {name = "纽约风味的芝士披萨";dough = "薄皮面团";sauce = "蕃茄酱";toppings.add("雷吉亚诺奶酪");}}
  • NYStyleVeggiePizza
      /*** 纽约风味的蔬菜披萨*/public class NYStyleVeggiePizza extends Pizza {public NYStyleVeggiePizza() {name = "纽约风味的蔬菜披萨";dough = "薄皮面团";sauce = "番茄酱";toppings.add("奶酪");toppings.add("大蒜");toppings.add("大葱");toppings.add("蘑菇");toppings.add("红辣椒");}}
    
  • NYStyleClamPizza
      /*** 纽约风味的蛤蜊披萨*/public class NYStyleClamPizza extends Pizza {public NYStyleClamPizza() {name = "纽约风味的蛤蜊披萨";dough = "薄皮面团";sauce = "番茄酱";toppings.add("雷吉亚诺奶酪");toppings.add("来自长岛海峡的新鲜蛤蜊");}}
    
  • NYStylePepperoniPizza
      /*** 纽约风味的意大利香肠披萨*/public class NYStylePepperoniPizza extends Pizza {public NYStylePepperoniPizza() {name = "纽约风味的意大利香肠披萨";dough = "薄皮面团";sauce = "咖喱酱";toppings.add("奶酪");toppings.add("香肠");toppings.add("大蒜");toppings.add("洋葱");toppings.add("蘑菇");toppings.add("红辣椒");}}

接下来我们继续实现芝加哥的披萨店

/*** 芝加哥的披萨店*/
public class ChicagoPizzaStore extends PizzaStore {@OverridePizza createPizza(String type) {if (type.equals("cheese")) {return new ChicaoStyleCheesePizza();} else if (type.equals("veggie")) {return new ChicaoStyleVeggiePizza();} else if (type.equals("clam")) {return new ChicaoStyleClamPizza();} else if (type.equals("pepperoni")) {return new ChicaoStylePepperoniPizza();}return null;}
}

自己可以模仿着纽约风味的披萨,写出ChicaoStyleCheesePizza,ChicaoStyleVeggiePizza,ChicaoStylePepperoniPizza,就像下面的ChicaoStyleCheesePizza一样

/*** 芝加哥风味的芝士披萨*/
public class ChicaoStyleCheesePizza extends Pizza {public ChicaoStyleCheesePizza() {name = "芝加哥风味的芝士披萨";dough = "厚皮面团";sauce = "蕃茄酱";toppings.add("雷吉亚诺奶酪");}
}

工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。

接下来我们回顾一下订单是如何生成披萨的,假如我们需要订购一款纽约风味的芝士披萨

  • 1.首先我们需要一个纽约的披萨店

      PizzaStore nyPizzaStore=new NYPizzaStore();
    
  • 2.现在有一个店了,那么我们就可以下订单了

      nyPizzaStore.orderPizza("cheese");
    

    调用nyPizzaStoze实例的ordePiza方法(达个方法被定义在PizzeStore中)。

  • 3.ordePiza方法调用createPizza方法;

  • 4.最后,披萨必须经过烘焙,裁剪,打包等才算完成

      pizza.prepare();pizza.bake();pizza.cut();pizza.box();
    

接下来我们正式订购一个披萨

public class Store {public static void main(String[] args) {//首先建立商店PizzaStore nyPizzaStore = new NYPizzaStore();PizzaStore chicaoStore = new ChicagoPizzaStore();Pizza pizza = nyPizzaStore.orderPizza("cheese");System.out.println("---------纽约风味的芝士披萨制作完成:"+pizza.toString()+"---------------------");pizza = chicaoStore.orderPizza("cheese");System.out.println("---------芝加哥风味的芝士披萨制作完成:"+pizza.toString()+"---------------------");}
}

运行结果如下:

认识工厂方法模式

所有工厂模式都用来封装对象的创建。
工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。让我们来看看这些类图,以了解有哪些组成元素:

  • 1.创建者类

  • 2.产品类

平行的类层级

我们已经看到,将一个orderPizza()方法和一个工厂方法联合起来,就可以成为一个框架。除此之外,工厂方法将生产知识封装进各个创建者,这样的做法,也可以被视为是一个框架。

定义工厂方法模式

工厂方法模式能够封装具体类型的实例化。如下面的类图所示,抽象的Creator提供了一个创建对象的方法的接口,也称为“工厂方法”。在抽象的Creator中,任何其他实现的方法,都可能使用到这个工厂方法所制造出来的产品,但只有子类真正实现这个工厂方法并创建产品

工厂方法让子类决定要实例化的类是哪一个。
希望不要理解错误,所谓的“决定”,并不是指模式允许子类本身在运行时做决定,而是指在编写创建者类时,不需要知道实际创建的产品是哪一个。选择了使用哪个子类,自然就决定了实际创建的产品是什么。

  • 当只有一个ConcreteCreator的时候,工厂方法模式有什么优点?

    尽管只有一个具体创建者,工厂方法模式依然很有用,因为它帮助我们将产品的“实现”从“使用”中解耦。如果增加产品或者改变产品的实现,Creator并不会受到影响(因为Creator与任何ConcreteProduct之间都不是紧耦合)。

对象依赖,依赖倒置原则

当我们直接实例化一个对象时,就是在依赖它的具体类
何为依赖倒置原则:
要依赖抽象,不要依赖具体类
首先,这个原则听起来很像是“针对接口编程,不针对实现编程”,然而这里更强调“抽象”。
这个原则说明了:不能让高层组件依赖低层组件,而且,不管高层或低层组件,“两者”都应该依赖于抽象。
所调“高层”组件.是由其他低层组件定义其行为的类。例如,PizzaStore是个高层组件.团为它的行为是由披萨定义的:PixzaStore创建所有不同的比萨对象,准备、烘烤、切片、装盒;而披萨本属于低层组件。
所以我们应用工厂模式之后,我们的类图应该更像下图所示:

在应用工厂方法之后,你将注意到,高层组件(也就是PizzaStore)和低层组件(也就是这些比萨)都依赖了Pizza抽象。想要遵循依赖倒置原则,工厂方法并非是唯的技巧,但却是最有威力的技巧之一。
下面的指导方针,能帮你避免在OO设计中违反依赖倒置原则:

  • 1.变量中不可以持有具体类的引用。

    如果使用New,就会持有具体类的引用。你可以改用工厂来避开这样的做法

  • 2.不要让类派生自具体类。

    如果派生自具体类,那么我们就会依赖具体类,请派生自一个抽象(接口或抽象类)

  • 3.不要覆盖基类中已经实现的方法

    如果覆盖基类已经=实现的方法,那么我们的基类就不是一个真正适合被继承的抽象。基类中已经实现的方法,应该由所有的子类共享。

接下来我们继续回到披萨店,为了保证披萨口感,我们需要建立一个原料工厂,来确保原料的一致,下面是纽约和芝加哥的两组不同的原料

建造原料工厂

现在,我们要建造一个工厂来生产原料;这个工厂将负责创建原料家族中的每一种原料。也就是说,工广将需要生产面团、酱料、芝士等。待会儿,你就会知道如何处理各个区域的差异了。
开始先为工厂定义一个接口,这个接口负责创建所有的原料:

/*** 原料工厂*/
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、ThickCrust-Dough。这些类可以在合适的区域间共享。
  • 3.然后你仍然需要将这一切组织起来,将新的原料工厂整合进旧的PizzaStore代码中
    对应的Dough,Sauce,Cheese,Veggies,Pepperoni,Clams如下
  • 1.Dough
      /*** 面团*/public interface Dough {public String toString();}
    
  • 2.Sauce
      /*** 酱*/public interface Sauce {String toString();}
    

其他的几个抽象接口也如上面两个一样,自己可以尝试编写
接下来我们实现纽约原料工厂,该工厂精于大蒜番茄酱料,Reggiano干酪,新鲜蛤蜊等

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {@Overridepublic Dough createDough() {return new ThinCrustDough();}@Overridepublic Sauce createSauce() {return new MarinaraSauce();}@Overridepublic Cheese createCheese() {return new ReggianoCheese();}@Overridepublic Veggies[] createVeggies() {Veggies veggies[] = {new Garlic(), new Onion(), new Mushroom(), new RedPepper()};return veggies;}@Overridepublic Pepperoni createPepperoni() {return new SlicedPepperoni();}@Overridepublic Clams createClam() {return new FeshClams();}
}

其中ThinCrustDough,MarinaraSauce等如下:

  • ThinCrustDough

      public class ThinCrustDough implements Dough{@Overridepublic String toString() {return "薄皮面团";}}
    
  • MarinaraSauce
      public class MarinaraSauce implements Sauce{@Overridepublic String toString() {return "蕃茄酱";}}
    

剩下的自己去编写即可,本文就不过多的赘述
接下来我们去实现芝加哥的食料工厂

/*** 芝加哥风味的食料工厂*/
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {@Overridepublic Dough createDough() {return new ThickCrustDough();}@Overridepublic Sauce createSauce() {return new PlumTomatoSauce();}@Overridepublic Cheese createCheese() {return new MozzarellaCheese();}@Overridepublic Veggies[] createVeggies() {Veggies veggies[] = {new BlackOlives(),new Spinach(),new Eggplant()};return veggies;}@Overridepublic Pepperoni createPepperoni() {return new SlicedPepperoni();}@Overridepublic Clams createClam() {return new FrozenClams();}
}

对应的ThickCrustDough,PlumTomatoSauce如下:

  • ThickCrustDough

      public class ThickCrustDough implements Dough {@Overridepublic String toString() {return "厚皮面团";}}
  • 2.PlumTomatoSauce
      public class PlumTomatoSauce implements Sauce{@Overridepublic String toString() {return "番茄酱配李子番茄";}}
    

其他的自己可以仿照着自己去编写
工厂均准备就绪,接下来我们需要重做披萨,让它只使用工厂生产出的原料

/*** 改版之后的披萨,只能使用我们工厂的原料*/
public abstract class Pizza02 {String name;Dough dough;Sauce sauce;Veggies veggies[];Cheese cheese;Pepperoni pepperoni;Clams clam;abstract void prepare();void bake() {System.out.println("Bake 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");}void setName(String name) {this.name = name;}String getName() {return name;}public String toString() {StringBuffer result = new StringBuffer();result.append("---- " + name + " ----\n");if (dough != null) {result.append(dough);result.append("\n");}if (sauce != null) {result.append(sauce);result.append("\n");}if (cheese != null) {result.append(cheese);result.append("\n");}if (veggies != null) {for (int i = 0; i < veggies.length; i++) {result.append(veggies[i]);if (i < veggies.length - 1) {result.append(", ");}}result.append("\n");}if (clam != null) {result.append(clam);result.append("\n");}if (pepperoni != null) {result.append(pepperoni);result.append("\n");}return result.toString();}
}

继续重做披萨
现在已经有了一个抽象比萨,可以开始创建纽约和芝加哥风味的比萨了。从今以后,加盟店必需直接从工厂取得原料,那些偷工减料的日子宣告结束了!
我们曾经写过工厂方法的代码,有NYCheesePizza和ChicagoCheesePizza类。比较一下这两个类,唯一的差别在于使用区域性的原料,至于比萨的做法都一样(面团+酱料+芝士),其他的比萨(蔬菜、蛤蝴等)也是如此。它们都依循着相同的准备步骤,只是使用不同的原料。
所以,其实我们不需要设计两个不同的类来处理不同风味的比萨,让原料工厂处理这种区域差异就可以了。下面是CheesePizza :

/*** 只能使用自己工厂的原料的芝士披萨*/
public class CheesePizza02 extends Pizza02 {PizzaIngredientFactory pizzaIngredientFactory;public CheesePizza02(PizzaIngredientFactory pizzaIngredientFactory) {this.pizzaIngredientFactory = pizzaIngredientFactory;}@Overridevoid prepare() {//preare方法会一步一步的创建芝士披萨,每当需要什么材料只需向食料工厂去要即可System.out.println("正在准备:" + name);dough = pizzaIngredientFactory.createDough();sauce = pizzaIngredientFactory.createSauce();cheese = pizzaIngredientFactory.createCheese();}
}

Pizza的代码利用相关的工厂生产原料。所生产的原料依赖所使用的工厂,Pizza类根本不关心这些原料,它只知道如何制作比萨。现在,Pizza和区域原料之间被解耦,无论原料工厂是在洛基山脉还是在西北沿岸地区,Pizza类都可以轻易地复用,完全没有问题。

接下来我们继续实现蛤蜊披萨

/*** 只能使用工厂原料制作的蛤蜊披萨*/
public class ClamPizza02 extends Pizza02 {PizzaIngredientFactory pizzaIngredientFactory;public ClamPizza02(PizzaIngredientFactory pizzaIngredientFactory) {this.pizzaIngredientFactory = pizzaIngredientFactory;}@Overridevoid prepare() {//preare方法会一步一步的创建芝士披萨,每当需要什么材料只需向食料工厂去要即可System.out.println("正在准备:" + name);dough = pizzaIngredientFactory.createDough();sauce = pizzaIngredientFactory.createSauce();cheese = pizzaIngredientFactory.createCheese();}
}

做完以上工作,我们基本完工,我们继续回到披萨店

/*** 使用工厂原料的披萨商店*/
public abstract class PizzaStore02 {public Pizza02 orderPizza(String type) {Pizza02 pizza;pizza = createPizza(type);//将创建披萨的方法从工厂中移回pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}abstract Pizza02 createPizza(String type);//把工厂对象移到这个方法中
}

继续构建纽约风味的披萨商店

/*** 使用工厂原料的纽约风味的披萨超市*/
public class NYPizzaStore02 extends PizzaStore02 {@OverridePizza02 createPizza(String type) {Pizza02 pizza = null;PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();//纽约店全用到纽约披萨原料工厂if (type.equals("cheese")) {pizza = new CheesePizza02(ingredientFactory);pizza.setName("纽约风味的芝士披萨");} else if (type.equals("veggie")) {pizza = new VeggiePizza02(ingredientFactory);pizza.setName("纽约风味的蔬菜披萨");} else if (type.equals("clam")) {pizza = new ClamPizza02(ingredientFactory);pizza.setName("纽约风味的蛤蜊披萨");} else if (type.equals("peoperoni")) {pizza = new PepperoniPizza02(ingredientFactory);pizza.setName("意大利辣味香肠");}return pizza;}
}

定义抽象工厂模式

下一篇:《设计模式05—单件模式》

设计模式04—工厂模式相关推荐

  1. Java设计模式(工厂模式>抽象工厂模式和原型模式)

    Java设计模式Ⅱ 1.工厂模式 1.1 简单工厂模式 1.2 工厂方法模式 2.抽象工厂模式 3.总结 4.原型模式 4.1 原型模式 4.2 浅拷贝 4.3 深拷贝 5.建造者模式 1.工厂模式 ...

  2. JavaScript设计模式--简单工厂模式例子---XHR工厂

    JavaScript设计模式--简单工厂模式例子---XHR工厂 第一步,Ajax操作接口(目的是起一个接口检测作用) (1)引入接口文件 //定义一个静态方法来实现接口与实现类的直接检验 //静态方 ...

  3. 三角形圆形创建与擦除java_设计模式---------------简单工厂模式

    设计模式---------------简单工厂模式 一.题目(Question) 使用简单工厂模式设计一个可以创建不同几何形状(如圆形.方形和三角形等)的绘图工具,每个几何图形都要有绘制draw()和 ...

  4. 策略模式和工厂模式的区别_设计模式之工厂模式-工厂方法模式

    设计模式之工厂模式-工厂方法模式 大家好,欢迎来到污污弹公司,今天司小司又接到了一个新活-披萨项目. 来源:凯哥Java(kaigejava) 需求: 披萨项目: 要方便披萨品种的扩展.要便于维护.要 ...

  5. Java 设计模式之工厂模式(二)

    原文地址:Java 设计模式之工厂模式(二) 博客地址:http://www.extlight.com 一.背景 本篇内容是 Java 设计模式创建型模式的第二篇.上一篇主题为 <Java 设计 ...

  6. 设计模式之工厂模式(三)

    上一次我们已经通过代码,简单的认识了工厂方法模式,具体的思路请移步到设计模式之工厂模式(二),进行查看.这次,让我们通过设计模式的思想,来好好认识下工厂方法模式. 创建者和产品 所有工厂模式都用来封装 ...

  7. php工厂模式和单例模式,php 设计模式之工厂模式、单例模式、注册树模式

    php 设计模式之工厂模式.单例模式.注册树模式 在软件工程中,创建型设计模式承担着对象创建的职责,尝试创建适合程序上下文的对象,对象创建设计模式的产生是由于软件工程设计的问题,具体说是向设计中增加复 ...

  8. 教你如何一篇博客读懂设计模式之—--工厂模式

    一篇博客读懂设计模式之-工厂模式 工厂模式在我们日常开发的时候经常用到,相信大家都有了一定的了解,工厂模式是一种创建对象的设计模式,它提供一种创建对象的最佳方式. 主要过程是: 定义一个创建对象的接口 ...

  9. 一篇博客读懂设计模式之---工厂模式

    设计模式之-工厂模式 工厂模式: 创建过程: 创建Shape接口 public interface Shape {void draw(); } 创建实现类: public class Circle i ...

  10. java 工厂模式详解_Java设计模式之工厂模式详解

    简单工厂其实并不是设计模式,只是一种编程习惯. 首先我们创建父类Cup,所有杯子类的父类.再创建它的子类BigCup和SmallCup类. public abstract class Cup { pu ...

最新文章

  1. UTF-8,UTF-16和UTF-32
  2. 一个操作内表的函数’CTVB_COMPARE_TABLES’
  3. yum groupinstall “Development Tools“查看其软件列表
  4. Scala中的/,%,++,--
  5. SpringMVC-学习笔记04【SpringMVC返回值类型及响应数据类型】
  6. SPOJ - TOURS Travelling tours(最小费用最大流)
  7. mysql 非等值条件 索引_慢SQL简述与定位
  8. 全面容器化:阿里5年带给我的最大收获
  9. 用python完成图形输出设备_用 Python 在多个输出设备上播放多个声音文件
  10. ascll编码表图片_ASCII编码表
  11. Java、前端页面中文乱码解决方式
  12. 无源贴片晶振四角引脚_有源晶振引脚图,有源晶振引脚定义
  13. 关于opencv的rows和cols的理解
  14. java电商网站建设教程_java开发电商系统实战开发视频教程
  15. oracle创建索引和删除索引
  16. 单独按戴尔笔记本f11键和f12键无法调节亮度了怎么办?用(Fn+F11键或者Fn+F12键就好)
  17. 绘画系统的简单实现(p5.js)
  18. win7计算机ftp清理记录,快速清除Win7使用记录的4则小技巧
  19. 一:Debian安装
  20. cantata测试工具_我如何构建和维护开源音乐播放器Cantata

热门文章

  1. 微信小程序页面跳转时数据传输
  2. 方向传感器新的替代方法详解
  3. 调频广播信号覆盖质量智能监测系统
  4. Microsoft Surface
  5. 论开展线上业务的纯粹度的重要性
  6. 炼数成金 课件整理数据分析与R语言 第1周
  7. 团队项目(3) -- 搭载于MSP430F6638_FFTB的仿《像素小鸟》小游戏
  8. 目标检测 (Detection) 算法综述
  9. mysql查出繁体文字_Mysql获取数据出现繁体显示为乱码的问题
  10. 再练动态规划——(4)涂抹果酱