定义 Provide an interface for creating families of related or dependent objects without specifying their concrete classes.(为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类) 优点 封装性:每个产品的实现类不是高层模块要关心的,高层模块只关心接口,抽象。对象由谁创建由工厂类负责。只要知道工厂类是谁就能够创建出一个需要的对象。 产品族内的约束为非公开状态:生产过程对调用工厂类的高层模块是透明的,具体产品族的约束是在工厂内实现的。 缺点 产品族的扩展十分困难。如果要增加一个新的产品族。会违背开闭原则。 使用场景 一个对象族(或是一组没有任何关系的对象)都有着相同的契约。举例:一组应用(文件编辑器、浏览器、图片编辑器等)在三个不同的平台发布。如:Linux,Unix,Windows。则Linux,Unix,Windows就是三个不同的产品族。而各个应用就是不同的产品等级 举例 便于理解,此处举例使用上面的场景。为了减少代码量,我们规定应用为图片编辑器,和浏览器(完全无关联),两个应用都发布在Linux,Windows平台。
代码 工厂部分 抽象工厂(接口或抽象 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.pattern.abstractfactory;import com.pattern.abstractfactory.products.LinuxSoftware;import com.pattern.abstractfactory.products.WindowsSoftware;public abstract class AbstractFactory { public abstract WindowsSoftware createWindowsSoftware () ; public abstract LinuxSoftware createLinuxSoftware () ; }
工厂实例:浏览器创建工厂(继承自抽象工厂 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.pattern.abstractfactory.impl;import com.pattern.abstractfactory.AbstractFactory;import com.pattern.abstractfactory.products.LinuxSoftware;import com.pattern.abstractfactory.products.WindowsSoftware;import com.pattern.abstractfactory.products.impl.LinuxBrowser;import com.pattern.abstractfactory.products.impl.WindowsBrowser;public class BrowserFactory extends AbstractFactory { @Override public WindowsSoftware createWindowsSoftware () { return new WindowsBrowser (); } @Override public LinuxSoftware createLinuxSoftware () { return new LinuxBrowser (); } }
工厂实例:编辑器创建工厂(继承自抽象工厂 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.pattern.abstractfactory.impl;import com.pattern.abstractfactory.AbstractFactory;import com.pattern.abstractfactory.products.LinuxSoftware;import com.pattern.abstractfactory.products.WindowsSoftware;import com.pattern.abstractfactory.products.impl.LinuxEditor;import com.pattern.abstractfactory.products.impl.WindowsEditor;public class EditorFactory extends AbstractFactory { @Override public WindowsSoftware createWindowsSoftware () { return new WindowsEditor (); } @Override public LinuxSoftware createLinuxSoftware () { return new LinuxEditor (); } }
产品1部分 产品族1抽象:Linux系统软件(接口或抽象 )
1 2 3 4 5 6 7 8 9 10 11 12 package com.pattern.abstractfactory.products;public abstract class LinuxSoftware { public void showPlatform () { System.out.println("当前的环境为Linux" ); } public abstract void showSoftware () ; public void linuxMethod () { System.out.println("这是Linux系统的独有方法" ); } }
产品1实例1:Linux文本编辑器(继承自产品族1抽象 )
1 2 3 4 5 6 7 8 9 10 11 12 package com.pattern.abstractfactory.products.impl;import com.pattern.abstractfactory.products.LinuxSoftware;public class LinuxEditor extends LinuxSoftware { @Override public void showSoftware () { System.out.println("这是一个Linux的文本编辑器" ); } }
产品1实例2:Linux浏览器(继承自产品族1抽象 )
1 2 3 4 5 6 7 8 9 10 11 12 package com.pattern.abstractfactory.products.impl;import com.pattern.abstractfactory.products.LinuxSoftware;public class LinuxEditor extends LinuxSoftware { @Override public void showSoftware () { System.out.println("这是一个Linux的文本编辑器" ); } }
产品2部分 产品族2抽象:Windows系统软件(接口或抽象 )
1 2 3 4 5 6 7 8 9 10 11 package com.pattern.abstractfactory.products;public abstract class WindowsSoftware { public void showPlatform () { System.out.println("当前的环境为Windows" ); } public abstract void showSoftware () ; public void windowsMethod () { System.out.println("这是Windows系统的独有方法" ); } }
产品2实例1:Windows文本编辑器(继承自产品族2抽象 )
1 2 3 4 5 6 7 8 9 10 11 package com.pattern.abstractfactory.products.impl;import com.pattern.abstractfactory.products.WindowsSoftware;public class WindowsEditor extends WindowsSoftware { @Override public void showSoftware () { System.out.println("这是一个Windows的文本编辑器" ); } }
产品2实例2:Windows浏览器(继承自产品族2抽象 )
1 2 3 4 5 6 7 8 9 10 11 12 package com.pattern.abstractfactory.products.impl;import com.pattern.abstractfactory.products.WindowsSoftware;public class WindowsBrowser extends WindowsSoftware { @Override public void showSoftware () { System.out.println("这是一个Windows的浏览器" ); } }
测试代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.pattern;import com.pattern.abstractfactory.AbstractFactory;import com.pattern.abstractfactory.impl.BrowserFactory;import com.pattern.abstractfactory.impl.EditorFactory;import com.pattern.abstractfactory.products.LinuxSoftware;import com.pattern.abstractfactory.products.WindowsSoftware;import com.pattern.abstractfactory.products.impl.WindowsBrowser;import com.pattern.abstractfactory.products.impl.WindowsEditor;import org.junit.Test;public class AbstractFactoryTest { @Test public void FactoryTest () { AbstractFactory editorFactory = new EditorFactory (); AbstractFactory browserFactory = new BrowserFactory (); System.out.println("--------------------" ); System.out.println("当前软件的运行环境为Windows" ); WindowsSoftware windowsBrowser = browserFactory.createWindowsSoftware(); WindowsSoftware windowsEditor = editorFactory.createWindowsSoftware(); windowsBrowser.showPlatform(); windowsBrowser.showSoftware(); windowsBrowser.windowsMethod(); windowsEditor.showPlatform(); windowsEditor.showSoftware(); windowsEditor.windowsMethod(); System.out.println("--------------------" ); System.out.println("软件重新部署了,使用环境为Linux" ); LinuxSoftware linuxBrowser = browserFactory.createLinuxSoftware(); LinuxSoftware linuxEditor = editorFactory.createLinuxSoftware(); linuxBrowser.showPlatform(); linuxBrowser.showSoftware(); linuxBrowser.linuxMethod(); linuxEditor.showPlatform(); linuxEditor.showSoftware(); linuxEditor.linuxMethod(); } }
类图 Idea自动生成的类图优点抽象,附上一个直观一点的
运行结果
扩展 下面我们来讨论扩展,分为产品族的扩展和产品等级的扩展。
产品族扩展 产品族的扩展是非常困难的,严重违反了开闭原则,拿上面例子来说就是扩展了一个新的软件平台,如Unix,下面是扩展需要的步骤。
定义一个新的接口或抽象,作为一个新的产品族。 为这个接口或抽象提供实例。 修改抽象工厂 ,为该工厂添加新产品族相关的方法修改抽象工厂的每一个实现类 ,来生产产品修改高层代码 从上面两处加红的地方已经严重违反的开闭原则了,抽象类和接口是一个契约,改变契约,所有与契约有关的代码都要修改!!! 产品等级扩展 产品等级的扩展很容易,符合开闭原则,拿上面的例子来说就是扩展了一个新的产品,如图片查看器,下面是扩展需要的步骤。
添加一个抽象工厂的实现类,用于创建新的产品等级(即新添加的产品)。 为不同的产品族加上该产品等级。即为每个产品族新增加一个实现类。 产品等级的扩展只需要两步,而且是完完全全通过扩展实现的,并没有对原来的代码造成侵入。 注意 有N个产品族,在抽象工厂类中就应该有N个创建方法。 有M个产品等级就应该有M个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务。 扩展困难是指产品族扩展困难,而产品等级扩展则很容易。符合开闭原则。 此处使用的是抽象类而非接口,实际上根据抽象工厂模式的定义,使用两者都可以,选择的关键就在于对于产品族而言,是否有共有的构造或者方法。 抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式