一个菜鸡JAVA后端的博客~

设计模式-抽象工厂模式

定义

  • Provide an interface for creating families of related or dependent objects without specifying their concrete classes.(为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类)

优点

  • 封装性:每个产品的实现类不是高层模块要关心的,高层模块只关心接口,抽象。对象由谁创建由工厂类负责。只要知道工厂类是谁就能够创建出一个需要的对象。
  • 产品族内的约束为非公开状态:生产过程对调用工厂类的高层模块是透明的,具体产品族的约束是在工厂内实现的。

缺点

  • 产品族的扩展十分困难。如果要增加一个新的产品族。会违背开闭原则。

使用场景

  • 一个对象族(或是一组没有任何关系的对象)都有着相同的契约。
    • 举例:
      • 一组应用(文件编辑器、浏览器、图片编辑器等)在三个不同的平台发布。如:Linux,Unix,Windows。则Linux,Unix,Windows就是三个不同的产品族。而各个应用就是不同的产品等级

举例

便于理解,此处举例使用上面的场景。为了减少代码量,我们规定应用为图片编辑器,和浏览器(完全无关联),两个应用都发布在Linux,Windows平台。

代码

工厂部分

抽象工厂(接口或抽象

package com.pattern.abstractfactory;

import com.pattern.abstractfactory.products.LinuxSoftware;
import com.pattern.abstractfactory.products.WindowsSoftware;

public abstract class AbstractFactory {
    /**
     * 用于创建Window系统的应用
     * @return 
     */
    public abstract WindowsSoftware createWindowsSoftware();
    /**
     * 用于创建Linux系统的应用
     * @return
     */
    public abstract LinuxSoftware createLinuxSoftware();
}

工厂实例:浏览器创建工厂(继承自抽象工厂

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();
    }
    
}

工厂实例:编辑器创建工厂(继承自抽象工厂

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系统软件(接口或抽象

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抽象

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抽象

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系统软件(接口或抽象

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抽象

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抽象

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的浏览器");
    }
    
}

测试代码

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");
        // 当前在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个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务。
  • 扩展困难是指产品族扩展困难,而产品等级扩展则很容易。符合开闭原则。
  • 此处使用的是抽象类而非接口,实际上根据抽象工厂模式的定义,使用两者都可以,选择的关键就在于对于产品族而言,是否有共有的构造或者方法。
  • 抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式

NOTE: 文章若无特别说明均为原创文章,如果要转载请保留出处!
0
分享