博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【设计模式】学习笔记5:工厂模式(Factory Method)
阅读量:4073 次
发布时间:2019-05-25

本文共 3188 字,大约阅读时间需要 10 分钟。

本文出自   

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

认识工厂模式

在简单工厂模式的SimpleFactory, 你确实可以创建比萨,但是其他部分:烘烤,切片等可能不同的店会有不同的差异。

如果我们要在其他地方开比萨店,比如在北京开比萨店,那么北京的制作比萨是不一样风格的,使用这个类的话,可能就要修改代码。所以把制作比萨的代码绑在PizzaStore里,这样做没有弹性。

那么要怎样做呢?

我们可以把createPizza()放回PizzaStore中,不过要把它设置成“抽象方法”,然后为每个不同地方的比萨店创建一个PizzaStore的子类:

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

有了一个PizzaStore的抽象类,让不同地方的比萨店都继承这个PizzaStore,每个子类各自决定如何制造比萨。

注意!这个做法是让PizzaStore的各个子类负责定义自己的createPizza()方法,这实际上是把决定推迟到了子类

记住,把决定推迟到了子类,这是工厂模式的重要特征!

现在我们来实现一个子类,创建一个芝加哥的比萨店:

public class ChicagoPizzaStore extends PizzaStore {	Pizza createPizza(String item) {        	if (item.equals("cheese")) {            		return new ChicagoStyleCheesePizza();        	} else if (item.equals("veggie")) {        	    	return new ChicagoStyleVeggiePizza();        	} else if (item.equals("clam")) {        	    	return new ChicagoStyleClamPizza();        	} else if (item.equals("pepperoni")) {            		return new ChicagoStylePepperoniPizza();        	} else return null;	}}
子类只要实现createPizza就可以了,这样子类可以自己决定要创建什么对象,而不用管其他东西,就很灵活了。

工厂模式定义

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

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

设计原则:依赖倒置

要依赖抽象,不要依赖具体类

看下面这个不使用工厂模式的比萨店,看它依赖了多少个具体类。

public class DependentPizzaStore { 	public Pizza createPizza(String style, String type) {		Pizza pizza = null;		if (style.equals("NY")) {			if (type.equals("cheese")) {				pizza = new NYStyleCheesePizza();			} else if (type.equals("veggie")) {				pizza = new NYStyleVeggiePizza();			} else if (type.equals("clam")) {				pizza = new NYStyleClamPizza();			} else if (type.equals("pepperoni")) {				pizza = new NYStylePepperoniPizza();			}		} else if (style.equals("Chicago")) {			if (type.equals("cheese")) {				pizza = new ChicagoStyleCheesePizza();			} else if (type.equals("veggie")) {				pizza = new ChicagoStyleVeggiePizza();			} else if (type.equals("clam")) {				pizza = new ChicagoStyleClamPizza();			} else if (type.equals("pepperoni")) {				pizza = new ChicagoStylePepperoniPizza();			}		} else {			System.out.println("Error: invalid type of pizza");			return null;		}		pizza.prepare();		pizza.bake();		pizza.cut();		pizza.box();		return pizza;	}}

当直接实例化一个对象时,就是在依赖它的具体类。

我们已经知道了“要针对接口编程,而不要针对具体编程”原则, 和依赖倒置原则原则很像,但是这里更强调“抽象”。

这个原则说明了:不能让高层组件以来低层组件,而且不管高层或低层组件,“两者”都应该依赖于抽象

所谓“高层”组件,是由其他低层组件定义其行为的类。例如,PizzaStore 是高层组件,因为它的行为是由比萨定义的:PizzaStore创建所有不同的比萨对象,而比萨本身属于低层组件。

在这个“比萨图”中,PizzaStore是“高层组件”,而比萨实现是“低层组件”, PizzStore依赖于这些具体比萨类。

我们应用“依赖倒置”原则来改变上面的类:

使用工厂方法后,高层组件(PizzaStore)和低层组件(那些具体比萨)都依赖了Pizza的抽象。

先要遵循依赖倒置原则,工厂方法并非是唯一的技巧,却是最有为例的技巧之一。

下面的知道方针可以帮助避免在OO设计中违反依赖倒置原则:

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

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

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

    如果派生自具体类,就会依赖这些具体类。请派生自一个抽象接口或抽象类。

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

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

你可能感兴趣的文章
linux内核学习(7)脱胎换骨解压缩的内核
查看>>
慢慢欣赏linux 内核模块引用
查看>>
kprobe学习
查看>>
React Native(一):搭建开发环境、出Hello World
查看>>
React Native(二):属性、状态
查看>>
JSX使用总结
查看>>
React Native(四):布局(使用Flexbox)
查看>>
React Native(七):Android双击Back键退出应用
查看>>
Android自定义apk名称、版本号自增
查看>>
【剑指offer】q50:树中结点的最近祖先
查看>>
二叉树的非递归遍历
查看>>
【leetcode】Reorder List (python)
查看>>
【leetcode】Linked List Cycle (python)
查看>>
【leetcode】Candy(python)
查看>>
【leetcode】Sum Root to leaf Numbers
查看>>
【leetcode】Pascal's Triangle II (python)
查看>>
如何成为编程高手
查看>>
本科生的编程水平到底有多高
查看>>
备忘:java中的递归
查看>>
Solr及Spring-Data-Solr入门学习
查看>>