0. 序
初学Java,制造对象都是new
,针对实现编程。这种情况使实例化对象公开的进行,同时也造成耦合。那么可以使用工厂方法来解决。
//例子 在应用程序中需要实例化一只鸭子
Duck duck;//鸭子接口
if(是玩具鸭)
duck= new 玩具鸭
if(是野鸭)
duck=new 野鸭
if(是家养鸭)
duck=new 家养鸭
...
//可见针对实现编程的缺点 而且一旦发生变化,例如鸭子实现类的改变,那么就要去改动系统中涉及到这部分的代码。
//实际上这部分 鸭子实例是变化的 而根据我们之前的原则,要取出变化的部分。并且 --开放闭合
即我们需要把实例化的代码从应用中抽离或者封装,使它们不会干扰其他部分。在内部只是保留一个接口即可(使用多态)
1. 工厂方法
简单点说,就是把创建对象的地方称为工厂,通过工厂来new一个对象提供给程序使用。这样**,就通过工厂来封装new对象的部分**。工厂来管理创建对象时的细节,无论他是玩具鸭子还是野鸭,交给工厂来处理,并最后返回一个Duck超类。如果以后我们需要增加鸭子类,只需要在工厂中做改变即可,不会涉及到引用鸭子类的部分。
//鸭子工厂
class DuckFactory{
public static Duck createDuck(String type){
Duck duck=null;
if(type=“玩具鸭”)
duck=new 玩具鸭;
....
return duck;//工厂返回制造的对象
}
//烤鸭子
class RoastDuck{
DuckFactory factory;//工厂 组合的方式
public RoastDuck(DuckFactory factory){
this.factory=factory;
}
public Duck roast(String type){
Duck duck=null;
//之前的代码
//if(type="玩具鸭")
// 玩具鸭;
//现在
duck=factory.createDuck(type);//根据type 工厂制作一个鸭子
...
}
}
}
//注意:这是一个简单工厂
简单工厂方法在我看来是比较简单的,复杂也只是存在于工厂与抽象工厂。工厂模式中一个工厂只能生产一种产品,而抽象工厂可以生产多个。例如鸭子工厂还能生产饮料产品。
定义:工厂方法定义了一个创建对象的接口,由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。
结合书上的 披萨店 可知:一个工厂可能存在多个子类工厂,而这些子类工厂生产的产品是自己决定的。所以要把制造产品的方法递给子类工厂。
在这里,Creator与ConcreteCreator直接的实现 可以解耦。在使用产品时,产生产品只需要使用Creator的多态即可,不需要依赖ConcreteCreator
P134 P135处解释很好
原则:依赖倒置:要依赖抽象,不要依赖具体类。
解释一下:以披萨店为例,如果针对实现去编程,那么就把生产披萨的方法交给披萨店,那么后续如果该披萨店要修改披萨种类数量,就要去披萨店修改代码。那么这里,披萨店依赖具体的披萨类。披萨店是高层组件,依赖实现。 如果在披萨店的类里使用组合的方式加入工厂,它的披萨类定义成披萨接口(多态),把披萨交给工厂来生产,那么就可以把披萨店与披萨的变化分开。
所谓倒置:在之前是高层组件依赖低层,现在是低层依赖高层
倒置前
倒置后
几个方针帮助遵循此原则:
- 变量不可用持有具体类的引用:如果使用new, 那不就是针对实现编程了?
- 不要让类派生自具体类:要依赖抽象,使用多态
- 不要覆盖基类中已经实现的方法:如果覆盖基类已实现的方法,那么这个基类就不是一个真正适合被继承的抽象。基类中已经实现的方法,应该由所有子类共享。
-
抽象工厂
抽象工厂实际上就是一个工厂能够生产多个产品。这些产品的实现取决于子类工厂。
//原料抽象工厂 public interface PizzaIngredientFactory { Dough createDough();//面团 Sauce createSauce();//酱汁 Cheese createCheese(); Veggies[] createVeggies(); Pepperoni createPepperoni(); Clams createClam(); } //子类工厂 //子类来决定抽象原料的实现 public class NYPizzaIngredientFactory implements PizzaIngredientFactory { @Override public Dough createDough() { return NY特色面团; } }
实际上,抽象工厂的每个方法看起来是工厂方法。它的每个方法都是抽象的,由子类去覆盖这些方法。抽象工厂方法的任务是定义一个负责创建一组产品的接口,这个接口每个方法都负责创建一个具体的产品。由抽象工厂子类去实现具体做法。
这一章通读下来,我发现我之前所用到的工厂方法只是简单工厂方法… 这一部分的内容书上的例子比较多且通俗易懂,这里就不做搬运了…
小结
-
简单工厂
就在工厂类里实例化对象
class SimplePizzaFactory{ Pizza createPizza(type){ Pizza pizza; if(type为奶酪) pizza=奶酪类型pizza; esle if ... } }
-
工厂方法
工厂定义一个实现产品的接口,由子类工厂去实现该接口 是一个继承的关系
abstract class PizzaFactory{ abstract Pizza createPizza(String type);//超类的接口 } class NYPFactory extends PizzaFactory{ Pizza createPizza(type){ //生产出NY的pizza } }
-
抽象工厂方法
对比工厂方法,工厂方法只生产一种产品–pizza ; 抽象工厂方法生产多种不同的产品–酱料/面团/佐料/…
//抽象工厂--原料 public interface PizzaIngredientFactory { Dough createDough();//面团 Sauce createSauce();//酱汁 Cheese createCheese(); Veggies[] createVeggies(); Pepperoni createPepperoni(); Clams createClam(); } //子类工厂 class NYPizzaIngredientFactory implements PizzaIngredientFactory{ //重写上述抽象工厂的方法 } //那么最后就可以在Pizza产生的过程中使用NYPizzaIngredientFactory来控制原料的使用与生产