1. 问题引出
当使用到“new”,就会想到“具体”
2. 找出会变化的部分,把它们从不变部分分离出来
但是如果需要更多地比萨类型
看见了吗,根据比萨的类型,我们实例化正确的具体类。
如果呢?我们需要添加Clam Pizza和Veggie Pizza比萨类型,我们也要将这些风味加入我们的菜单,同时删除一些卖的不好的比萨
很明显的,如果实例化“某些具体类”,将不断地修改orderPizza,导致无法对修改关闭,所以此时我们已经知道了,哪些会改变,哪些不会改变,该是使用封装的时候了。
3. 封装创建对象的代码
我们将上面这部分代码,封装到另一个对象中,这个新对象只管如何创建比萨。
我们称这个对象为“工厂”,orderPizza()就变成了此“工厂”的客户。
4. 建立一个简单的比萨工厂
这样做的好处: 代码复用,不光orderPizza()方法可以成为客户,其他类也能成为客户;
1. 工厂可以设置为静态的类,因为其实并不需要创建对象来调用工厂方法。
5. 重写PizzaStore类
6. 这就是简单工厂
上面所使用的套路不是一个设计模式,其实是一种编程习惯而已,称之为“简单工厂”,请记住:这不是工厂模式。
7. 加盟比萨店
问题:如果想要多一些质量控制,比如说:加盟店采用工厂创建比萨,但是其他部分采用他们自创的流程:流程有些地方有些差异。
所以呢,我们希望建立一个框架,把加盟店和创建比萨捆绑在一起的同时又保持一定的弹性。
将createPizza()放入PizzaStore类中
8. 允许子类做决定
我们让各个地区的pizza店继承PizzaStore,实现createPizza方法,这样可以简单地说由子类各自决定如何制造比萨。下面是实现的类图
子类如何做决定:orderPizza调用createPizza时,某个比萨店子类将负责创建比萨。做哪一种比萨,当然由具体的比萨店来做决定。严格来说,是顾客决定。
工厂方法:抽象,必须返回一个产品,可以需要参数也可以不需要。
我们来实现比萨本身:
9.认识工厂方法模式
重点:所有的工厂模式都用来封装对象的创建。
另一个观点,它们是平行的类层级
下面是工厂方法通用结构
问题:当有一个concreteCreator的时候,工厂方法模式有什么优点?
尽管只有一个具体创建者,工厂方法依然很有用,因为它帮助我们将产品的“实现”从“使用”中解耦,如果增加产品或者改变产品的实现,creator并不会收到影响,因为它们不是紧耦合。
问题:如果说纽约和芝加哥的商店是利用简单工厂创建的,这样说是否正确?
不对啊,因为创建的方法是商店扩展自一个类,而简单工厂是另外单独的一个类的方法去创建对象。
问题:简单工厂和工厂方法之间的差异,我依然感到困惑。他们看起来很类似,差别在于,在工厂方法中,返回比萨的类是子类,能解释一下吗?
子类的确看上去很像简单工厂,简单工厂把全部事情在一个地方处理完了,然后工厂方法是创建一个框架,让子类决定要如何实现。比方说,orderPizza方法依赖工厂方法创建具体类,并制造出的比萨是什么?可通过继承PizzaStore类,决定实际制造出比萨是什么?简单工厂的做法,可以将对象的创建封装起来,简单工厂不具备工厂方法的弹性,简单工厂不能变更正在创建的产品。
10. 看看对象依赖
设计原则(依赖倒置原则):要依赖抽象,不要依赖具体类。
倒置思维方式如下
下面三个指导方针帮助我们遵循此原则:
1. 变量不可以持有具体类的引用:如果使用new,order方法会持有具体类的引用,我们利用工厂来避开这样的做法;
2. 不要让类派生自具体类:如果派生自具体类,就会依赖具体类,请派生自一个抽象(接口或抽象类);
3. 不要覆盖基类中已经实现的方法:如果覆盖已经实现的方法,那么你的基类不是一个真正被继承的抽象,基类中已实现的方法,应该由所有子类共享。
11. 再回到比萨店
12. 原料家族
纽约使用一组原料,芝加哥使用另一组原料等等(出现了和比萨一样的问题)
基于此,我们创建原料工厂,也就是一个工厂加若干个不同地区工厂的子类。
我们重做比萨,prepare声明为抽象的,方便不同的比萨采用不同的原料。
我们实现比萨的一个子类
所以,比萨利用相关工厂生产原料,比萨只使用原料,不管如何实现原料,所以比萨和原料之间被解耦。
再回到纽约的比萨店,看看我们和具体的工厂连上线了
13. 基于以上我们做了些什么?
1. 引入了商店的子类将商店和比萨解耦;
2. 引入了新类型的工厂将比萨和原料解耦。
14. 定义抽象工厂模式
提供一个接口,用于创建相关或依赖对象的的家族,而不需要明确指定具体类。
抽象工厂允许客户使用抽象的接口来创建一组有关的产品,而不需要知道(关心)实际产出的具体产品是什么。这样依赖,客户就与具体的产品中被解耦,让我们看看类图。
注意到了吗,其实抽象工厂的方法都是工厂方法。
总结:
1. 所有的工厂都是用来封装对象的创建;
2. 简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类解耦;
3. 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象;
4. 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中;
5. 所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合;
6. 工厂方法允许类将实例化延迟到子类进行;
7. 抽象工厂创建相关的对象家族,而不需要依赖它们的具体类;
8. 依赖倒置原则:知道我们避免依赖具体类型,而要尽量依赖抽象;
9. 工厂是很有威力的技巧,帮助我们针对抽象编程,而不针对具体类编程。
简单工程模式、工厂方法模式以及抽象工厂模式的区别见:https://m.php.cn/java/guide/435553.html