解决对象的创建问题
------工厂模式(简单工厂、工厂方法、抽象工厂)
一、简单工厂模式
1、问题描述
(1)假设你有一个比萨店,根据比萨类型,制造比萨。
(2)新的需求:GreekPizza卖得不好,把它去掉。新增一些流行口味的比萨:ClamPizza、VeggiePizza
此处暴露问题:没有对修改封闭。有新的需求,还要到这里修改。
2、解决办法:封装创建对象的代码(封装变化)
实现如下:
注:这似乎只是把问题搬到了另一个对象中罢了,问题好像还是存在?值得一提的是,SimplePizzaFactory可能很多地方都用到它,当以后有新需求时,只需修改这个类就好了。
3、简单工厂模式
简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。
比萨店类图:
二、工厂方法模式
1、问题描述
加盟比萨店:所有店都有统一的流程,允许各自制作该区域的风味。
2、简单工厂解决:缺乏统一流程。
NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = PizzaStore("nyFactory");
nyStore.orderPizza("Veggie");
ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
PizzaStore chicagoStore = PizzaStore("chicagoFactory");
chicagoStore.orderPizza("Veggie");
缺点:各自的店可能采用自己的流程:如不要切片、使用其它盒子等。
3、工厂方法解决
简单工厂是由一个对象负责所有具体类的实例化,现在通过对PizzaStore做一些小转变,
由一群子类负责实例化。
(1)比萨店超类框架
(2)子类实现工厂方法
4、认识工厂方法
5、定义工厂方法模式
(1)定义:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
(2)类图:
(3)与简单工厂比较:简单工厂把全部的事情,在一个地方都处理完了,然而工厂方法却是创建一个框架,让子类决定如何实现。
(4)封装变化:把创建对象的代码集中在一个对象或方法中,可以避免代码中的重复,并且更方便以后的维护。这也意味着客户在实例化对象时,只会依赖接口,而不是具体类。这样代码更有弹性,可以应对未来扩展。
6、设计原则:依赖倒置
(1)定义:要依赖抽象,不要依赖具体类。
不能让高层组件依赖低层组件,而且,不管高层或低层组件,“两者”都应该依赖抽象
(2)应用
(3)指导方针
a. 变量不可以持有具体类的引用。
如果使用new,就会持有具体类的引用。你可以改用工厂来避开这样的做法。
b. 不要让类派生自具体类。
请派生一个抽象(接口或抽象类)
c. 不要覆盖基类中已实现的方法。
如果覆盖基类已实现的方法,那么你的基类就不是一个真正适合被继承的抽象。基类中已实现的方法,应该由子类共享。
注:灵活运用,尽量达到这个原则,而不是随时都要遵循这个原则。
三、抽象工厂模式
1、问题描述
对于NYCheesePizza和ChicagoPizza,唯一的差别在于使用区域性的原料,没必要整两个类,让原料工厂处理这种区域差异就可以了。
2、解决办法
3、抽象工厂模式:创建一组对象
(1)定义
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
(2)类图
4、比较工厂方法与抽象工厂
(1)都是用于创建对象,工厂方法使用继承扩展一个类,并覆盖它的工厂方法。其实整个工厂方法,就是通过子类来创建对象。
而抽象工厂是用组合,把一群相关的产品集合起来。
(2)工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象。
(3)抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中。是创建一组对象。