女娲的失误
工厂模式中讲了女娲造人的故事。人是造出来了,世界也热闹了,可是低头一看,都是清一色的类型,缺少关爱、仇恨、喜怒哀乐等情绪,人类的生命太平淡了,女娲一想,猛然一拍脑袋,忘记给人类定义性别了,那怎么办?抹掉重来,于是人类经过一次大洗礼,所有的人种都消灭掉了,世界又是空无一物,寂静而又寂寞。
由于女娲之前的准备工作花费了非常大的精力,比如准备黄土、八卦炉等,从头开始建立所有的事物也是不可能的,那就想在现有的条件下重新造人,尽可能旧物利用嘛。人种 (
Product

产品类分析完毕了,生产的工厂类(八卦炉)该怎么改造呢?只有一个生产设备,要么生产出来的全都是男性,要么都是女性。那不行呀,这么翻天覆地的改造就是为了产生不同 性别的人类。有办法了!把目前已经有的生产设备——八卦炉拆开,于是女娲就使用了“八 卦复制术”,把原先的八卦炉一个变两个,并且略加修改,就成了女性八卦炉(只生产女性 人种)和男性八卦炉(只生产男性人种),于是乎女娲就开始准备生产了,其类图如图9-2所示。
这个类图虽然大,但是比较简单。
Java
N
HumanFactory
Y
X
Y
Human

<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 人种接口 * @author: Jacob * @create: 2020-08-18 10:57 **/public interface Human { //每个人种都有相应的颜色 public void getColor(); //人类会说话 public void talk(); //每个人都有性别 public void getSex();}人种有三个抽象类,负责人种的抽象属性定义:肤色和语言。白色人种、黑色人种、黄 色人种分别如代码。
代码语言:javascript代码运行次数:0运行复制<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 黑色人种 * @author: Jacob * @create: 2020-08-18 11:14 **/public abstract class AbstractBlackHuman implements Human{ //黑色人种的皮肤颜色是黑色的 @Override public void getColor() { System.out.println("黑色人种的皮肤颜色是黑色的!"); } //黑色人种讲话 @Override public void talk() { System.out.println("黑色人种会说话,一般人听不懂。"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 白色人种 * @author: Jacob * @create: 2020-08-18 11:13 **/public abstract class AbstractWhiteHuman implements Human { //白色人种的皮肤颜色是白色的 @Override public void getColor() { System.out.println("白色人种的皮肤颜色是白色的!"); } //白色人种讲话 @Override public void talk() { System.out.println("白色人种会说话,一般说的都是单字节。"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 黄色人种 * @author: Jacob * @create: 2020-08-18 11:16 **/public abstract class AbstractYellowHuman implements Human { //黄色人种的皮肤颜色是黄色的 @Override public void getColor() { System.out.println("黄色人种的皮肤颜色是黄色的!"); } //黄色人种讲话 @Override public void talk() { System.out.println("黄色人种会说话,一般说的都是双字节。"); } }每个抽象类都有两个实现类,分别实现公共的最细节、最具体的事物:肤色和语言。具 体的实现类实现肤色、性别定义。
代码语言:javascript代码运行次数:0运行复制<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 黑色女性人种 * @author: Jacob * @create: 2020-08-18 11:21 **/public class FemaleBlackHuman extends AbstractBlackHuman { @Override public void getSex() { System.out.println("黑色女性人种"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 黑色男性人种 * @author: Jacob * @create: 2020-08-18 11:22 **/public class MaleBlackHuman extends AbstractBlackHuman{ @Override public void getSex() { System.out.println("黑色男性人种"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 白色女性人种 * @author: Jacob * @create: 2020-08-18 11:20 **/public class FemaleWhiteHuman extends AbstractWhiteHuman{ @Override public void getSex() { System.out.println("白色女性人种"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 白色男性人种 * @author: Jacob * @create: 2020-08-18 11:20 **/public class MaleWhiteHuman extends AbstractWhiteHuman{ @Override public void getSex() { System.out.println("白色男性人种"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 黄色女性人种 * @author: Jacob * @create: 2020-08-18 11:17 **/public class FemaleYellowHuman extends AbstractYellowHuman { @Override public void getSex() { System.out.println("黄色女性人种"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 黄色男性人种 * @author: Jacob * @create: 2020-08-18 11:18 **/public class MaleYellowHuman extends AbstractYellowHuman { @Override public void getSex() { System.out.println("黄色男性人种"); }}到此为止,我们已经把真实世界的人种都定义出来了,剩下的工作就是怎么制造人类。
代码语言:javascript代码运行次数:0运行复制<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 八卦炉定义 * @author: Jacob * @create: 2020-08-18 17:47 **/public interface HumanFactory { //制造一个黄色人种 public Human createYellowHuman(); //制造一个白色人种 public Human createWhiteHuman(); //制造一个黑色人种 public Human createBlackHuman();}在接口中,我们看到八卦炉是可以生产出不同肤色人种的(当然了,女娲的失误嘛), 那它有多少个八卦炉呢?两个,分别生产女性和男性,女性和男性八卦炉。
代码语言:javascript代码运行次数:0运行复制<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 生产女性的八卦炉 * @author: Jacob * @create: 2020-08-18 17:48 **/public class FemaleFactory implements HumanFactory { //生产出黄人女性 @Override public Human createYellowHuman() { return new FemaleYellowHuman(); } //生产出白人女性 @Override public Human createWhiteHuman() { return new FemaleWhiteHuman(); } //生产出黑人女性 @Override public Human createBlackHuman() { return new FemaleBlackHuman(); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 生产男性的八卦炉 * @author: Jacob * @create: 2020-08-18 17:49 **/public class MaleFactory implements HumanFactory { //生产出黑人男性 @Override public Human createBlackHuman() { return new MaleBlackHuman(); } //生产出白人男性 @Override public Human createWhiteHuman() { return new MaleWhiteHuman(); } //生产出黄人男性 @Override public Human createYellowHuman() { return new MaleYellowHuman(); }}人种有了,八卦炉也有了,我们就来重现一下当年女娲造人的光景。
代码语言:javascript代码运行次数:0运行复制<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 女娲重造人类 * @author: Jacob * @create: 2020-08-18 17:51 **/public class NvWa { public static void main(String[] args) { //第一条生产线,男性生产线 HumanFactory maleHumanFactory = new MaleFactory(); //第二条生产线,女性生产线 HumanFactory femaleHumanFactory = new FemaleFactory(); //生产线建立完毕,开始生产人了: Human femaleYellowHuman = femaleHumanFactory.createYellowHuman(); Human femaleBlackHuman = femaleHumanFactory.createBlackHuman(); Human femaleWhiteHuman = femaleHumanFactory.createWhiteHuman(); System.out.println("---生产一个黄色女性---"); femaleYellowHuman.getColor(); femaleYellowHuman.talk(); femaleYellowHuman.getSex(); System.out.println("---生产一个黑色女性---"); femaleBlackHuman.getColor(); femaleBlackHuman.talk(); femaleBlackHuman.getSex(); System.out.println("---生产一个白色女性---"); femaleWhiteHuman.getColor(); femaleWhiteHuman.talk(); femaleWhiteHuman.getSex(); Human maleYellowHuman = maleHumanFactory.createYellowHuman(); Human maleBlackHuman = maleHumanFactory.createBlackHuman(); Human maleWhiteHuman = maleHumanFactory.createWhiteHuman(); System.out.println("\n---生产一个黄色男性---"); femaleWhiteHuman.getColor(); maleYellowHuman.talk(); maleYellowHuman.getSex(); System.out.println("\n---生产一个黄色男性---"); maleBlackHuman.getColor(); maleBlackHuman.talk(); maleBlackHuman.getSex(); System.out.println("\n---生产一个白色男性---"); maleWhiteHuman.getColor(); maleWhiteHuman.talk(); maleWhiteHuman.getSex(); } }<pre class="brush:php;toolbar:false;">运行结果如下所示:---生产一个黄色女性---黄色人种的皮肤颜色是黄色的!黄色人种会说话,一般说的都是双字节。黄色女性人种---生产一个黑色女性---黑色人种的皮肤颜色是黑色的!黑色人种会说话,一般人听不懂。黑色女性人种---生产一个白色女性---白色人种的皮肤颜色是白色的!白色人种会说话,一般说的都是单字节。白色女性人种---生产一个黄色男性---白色人种的皮肤颜色是白色的!黄色人种会说话,一般说的都是双字节。黄色男性人种---生产一个黄色男性---黑色人种的皮肤颜色是黑色的!黑色人种会说话,一般人听不懂。黑色男性人种---生产一个白色男性---白色人种的皮肤颜色是白色的!白色人种会说话,一般说的都是单字节。白色男性人种
各种肤色的男性、女性都制造出来了,两性之间产生了相互吸引力,于是情感产生,这 个世界就多了一种小说的题材“爱情”。回头来想想我们的设计,不知道大家有没有去过工厂,每个工厂分很多车间,每个车间又分多条生产线,分别生产不同的产品,我们可以把八卦炉比喻为车间,把八卦炉生产的工艺(生产白人、黑人还是黄人)称为生产线,如此来看就是一个女性生产车间,专门生产各种肤色的女性,一个是男性生产车间,专门生产各种肤色男性,生产完毕就可以在系统外组装,什么是组装?嘿嘿,自己思考!在这样的设计下,各个车间和各条生产线的职责非常明确,在车间内各个生产出来的产品可以有耦合关系,你 要知道世界上黑、黄、白人种的比例是:
1∶4∶6
抽象工厂模式(
Abstract Factory Pattern
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。我们来看看抽象工厂的通用源代码,首先有两个互相影响的产品线(也叫做产品族),例如制造汽车的左侧门和右侧门,这两个应 该是数量相等的——两个对象之间的约束,每个型号的车门都是不一样的,这是产品等级结 构约束的,我们先看看两个产品族的类图。

注意类图上的圈圈、框框相对应,两个抽象的产品类可以有关系,例如共同继承或实现 一个抽象类或接口。
代码语言:javascript代码运行次数:0运行复制<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 抽象产品A类 * @author: Jacob * @create: 2020-08-18 17:57 **/public abstract class AbstractProductA { //每个产品共有的方法 public void shareMethod() { System.out.println("每个产品A共有的方法"); } //每个产品相同方法,不同实现 public abstract void doSomething();}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 产品A1的实现类 * @author: Jacob * @create: 2020-08-18 17:58 **/public class ProductA1 extends AbstractProductA { @Override public void doSomething() { System.out.println("产品A1的实现方法"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 产品A1的实现类 * @author: Jacob * @create: 2020-08-18 17:58 **/public class ProductA2 extends AbstractProductA { @Override public void doSomething() { System.out.println("产品A2的实现方法"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 抽象产品B类 * @author: Jacob * @create: 2020-08-18 17:57 **/public abstract class AbstractProductB { //每个产品共有的方法 public void shareMethod() { System.out.println("每个产品B共有的方法"); } //每个产品相同方法,不同实现 public abstract void doSomething();}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 产品B1实现类 * @author: Jacob * @create: 2020-08-18 17:58 **/public class ProductB1 extends AbstractProductB { @Override public void doSomething() { System.out.println("产品B1的实现方法"); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 产品B2实现类 * @author: Jacob * @create: 2020-08-18 17:58 **/public class ProductB2 extends AbstractProductB { @Override public void doSomething() { System.out.println("产品B2的实现方法"); }}抽象工厂类
AbstractCreator
<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 抽象工厂类 * @author: Jacob * @create: 2020-08-18 18:02 **/public abstract class AbstractCreator { //创建A产品家族 public abstract AbstractProductA createProductA(); //创建B产品家族 public abstract AbstractProductB createProductB();}注意:有N个产品族,在抽象工厂类中就应该有
N
如何创建一个产品,则是由具体的实现类来完成的。
代码语言:javascript代码运行次数:0运行复制<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 产品等级1的实现类 * @author: Jacob * @create: 2020-08-18 18:03 **/public class Creator1 extends AbstractCreator { //只生产产品等级为1的A产品 @Override public AbstractProductA createProductA() { return new ProductA1(); } //只生产产品等级为1的B产品 @Override public AbstractProductB createProductB() { return new ProductB1(); }}<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 产品等级1的实现类 * @author: Jacob * @create: 2020-08-18 18:03 **/public class Creator2 extends AbstractCreator { //只生产产品等级为1的A产品 @Override public AbstractProductA createProductA() { return new ProductA2(); } //只生产产品等级为1的B产品 @Override public AbstractProductB createProductB() { return new ProductB2(); }}注意:有
M
M
在具体的业务中如何产生一个与实现无关的对象呢?
代码语言:javascript代码运行次数:0运行复制<pre class="brush:php;toolbar:false;">/** * @program: DesignMode * @description: 场景类 * @author: Jacob * @create: 2020-08-18 18:08 **/public class Client { public static void main(String[] args) { //定义出两个工厂 AbstractCreator creator1 = new Creator1(); AbstractCreator creator2 = new Creator2(); //产生A1对象 AbstractProductA a1 = creator1.createProductA(); a1.doSomething(); a1.shareMethod(); //产生A2对象 AbstractProductA a2 = creator2.createProductA(); a2.doSomething(); a2.shareMethod(); //产生B1对象 AbstractProductB b1 = creator1.createProductB(); b1.doSomething(); b1.shareMethod(); //产生B2对象 AbstractProductB b2 = creator2.createProductB(); b2.doSomething(); b2.shareMethod(); }}在场景类中,没有任何一个方法与实现类有关系,对于一个产品来说,我们只要知道它的工厂方法就可以直接产生一个产品对象,无须关心它的实现类。
代码语言:javascript代码运行次数:0运行复制<pre class="brush:php;toolbar:false;">运行结果如下所示:产品A1的实现方法每个产品A共有的方法产品A2的实现方法每个产品A共有的方法产品B1的实现方法每个产品B共有的方法产品B2的实现方法每个产品B共有的方法
抽象工厂模式的最大缺点就是产品族扩展非常困难,为什么这么说呢?我们以通用代码 为例,如果要增加一个产品C,也就是说产品家族由原来的2个增加到3个,看看我们的程序 有多大改动吧!抽象类
AbstractCreator
createProductC()
抽象工厂模式的使用场景定义非常简单:一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。什么意思呢?例如一个文本编辑器和一个图片处理器,都是软件实体,但是
*nix
Windows
在抽象工厂模式的缺点中,我们提到抽象工厂模式的产品族扩展比较困难,但是一定要清楚,是产品族扩展困难,而不是产品等级。在该模式下,产品等级是非常容易扩展的,增加一个产品等级,只要增加一个工厂类负责新增加出来的产品生产任务即可。也就是说横向 扩展容易,纵向扩展困难。以人类为例子,产品等级中只有男、女两个性别,现实世界还有一种性别:双性人,既是男人也是女人(俗语就是阴阳人),那我们要扩展这个产品等级也是非常容易的,增加三个产品类,分别对应不同的肤色,然后再创建一个工厂类,专门负责不同肤色人的双性人的创建任务,完全通过扩展来实现需求的变更,从这一点上看,抽象工厂模式是符合开闭原则的。
最佳实践一个模式在什么情况下才能够使用,是很多读者比较困惑的地方。抽象工厂模式是一个简单的模式,使用的场景非常多,大家在软件产品开发过程中,涉及不同操作系统的时候, 都可以考虑使用抽象工厂模式,例如一个应用,需要在三个不同平台(
Windows
Linux
Android
UI
以上就是设计模式 之 抽象工厂模式的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号