《Head-First-设计模式》笔记5-工厂方法模式
定义
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
现在对该系统进行修改,不再设计一个披萨工厂类来统一负责所有产品的创建,而是将具体披萨的创建过程交给专门的工厂子类(不同的加盟店)去完成,我们先定义一个抽象的披萨工厂类,再定义具体的工厂类来生成不同的披萨,它们实现在抽象披萨工厂类中定义的方法。这种抽象化的结果使这种结构可以在不修改具体工厂类的情况下引进新的产品,如果出现新的披萨类型,只需要为这种新类型的披萨创建一个具体的工厂类就可以获得该新披萨的实例,这一特点无疑使得工厂方法模式具有超越简单工厂模式的优越性,更加符合“开闭原则”。
代码实现
改造后的 PizzaStore 的代码
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
abstract Pizza createPizza(String type); // 允许子类做决定
}
子类
public class NYPizzaSrore extends PizzaStore {
@Override
Pizza createPizza(String type) {
if (type.equals("cheese")) {
return new CheesePizza();
} else if (type.equals("greek")) {
return new GreekPizza();
}
return null;
}
}
使用
PizzaStore nyStore = new NYPizzaSrore();
Pizza pizza = nyStore.orderPizza("cheese");
模式结构
工厂方法模式包含如下角色:
- Product:抽象产品
- ConcreteProduct:具体产品
- Factory:抽象工厂
- ConcreteFactory:具体工厂
优缺点
工厂方法模式的优点
- 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
- 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
- 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
工厂方法模式的缺点
- 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
工厂方法和简单工厂的区别
- Factory Method 的核心是一个抽象工厂类,而 Simple Factory 把核心放在一个具体类上。
- Factory Method 的具体工厂类都有共同的接口,或者有共同的抽象父类。
- 当系统扩展需要添加新的产品对象时,Factory Method仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。而 Simple Factory 在添加新产品对象后不得不修改工厂方法,扩展性不好。
依赖倒置原则
要依赖抽象,不要依赖具体类。
不要让“高层组件”依赖“低层组件”,而且,不管“高层组件”还是“低层组件”,两者都应该依赖于抽象。
上述例子中的披萨店是 高层组件,具体的披萨是底层组件,而比萨店是抽象的,北京加盟店是具体的;而比萨是抽象的,北京糖味披萨是具体的;
避免违反该原则的几个方针:
- 变量不可以持有具体类的引用。
如果使用new,就会持有具体类的引用,可以使用工厂来避开这种引用。 - 不要让类派生自具体类。
如果派生自具体类,就会依赖具体类,可以派生自抽象或接口。 - 不要覆盖基类中已实现的方法。
如果覆盖基类中已实现的方法,那么基类就不是一个真正适合被继承的类。基类中已实现的方法应该被所有子类所共享。
依赖倒置原则,究竟倒置在哪里? 比较下面两幅图,你会注意到底层组件依赖现在依赖高层组件,而高层组件也依赖于相同的抽象 Pizza 类;
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com
文章标题:《Head-First-设计模式》笔记5-工厂方法模式
文章字数:1.4k
本文作者:Bin
发布时间:2018-07-08, 21:43:14
最后更新:2019-08-06, 00:07:35
原始链接:http://coolview.github.io/2018/07/08/Head-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E3%80%8AHead-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%8B%E7%AC%94%E8%AE%B05-%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。