前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >抽象工厂模式(选择产品簇)

抽象工厂模式(选择产品簇)

作者头像
幺鹿
发布2018-08-21 15:58:58
9900
发布2018-08-21 15:58:58
举报
文章被收录于专栏:Java呓语

回顾众多工厂模式

简单工厂模式

对简单工厂模式还不了解的可以查看下我的历史文章 简单工厂模式,简单工厂模式的核心是使用工厂实现选择创建产品实现,这应该很好理解。

简单工厂模式

工厂方法模式

对工厂方法模式还不了解的可以查看下我的历史文工厂方法模式。工厂方法模式的核心是将选择创建产品实现的过程,延迟到子类去完成,这也是相对比较好理解的模式。

工厂方法模式

抽象工厂模式的理念

第一节的回顾,我们复习了简单工厂与工厂方法模式。由此我们也会使用 UML 图线画出对抽象工厂模式的理解,然后我们在对比三张 UML 图来分析他们之间的设计是如何演进或取舍的。

抽象工厂模式

抽象工厂模式强调了产品簇的概念,那么什么是产品簇呢?在抽象工厂模式中,产品簇是指工厂生产出的产品们之间彼此具备强关联。比如:AK47工厂生产的 AK47步枪、AK47专配的子弹,一旦 AK47装错了子弹是无法正常开枪的(甚至会炸膛)。


抽象工厂模式与工厂方法模式的差异

刚开始接触抽象工厂模式的时候,我就是不能理解抽象工厂模式与工厂方法模式的区别,也许屏幕前的你也有一样的困惑。但经过一段时间时间的思考与实践,我逐渐的明白它们之间的差异。

移动手机大卖场

工厂方法模式生产产品的形式就像 移动手机大卖场(上图)。卖场里面只卖手机,这些手机里面可能有 三星、华为、OPPO、金立、苹果、HTC、Nokia 等类别,但无论如何它都没有跳出手机的范畴。因此想买手机的客户,直接去大卖场总能挑选到心仪的手机,因为手机(工厂生产的产品实例)太多了。

苹果零售店

而抽象工厂模式生产产品的形式则更像是苹果零售店(上图),除了卖手机之外还提供Mac、路由器、耳机、iPad、iPod 等电子产品。作为一个对品质(逼格)有要求的客户,会直接去苹果零售店里购买手机,一时兴起再买一台 Mac 也是可以的。

无论手机大卖场苹果零售店都是可以买到手机的,但是针对的客户群体显然是不一样的。同样的,工厂方法模式 与 抽象工厂模式 针对的客户群体也是不一样的,不过它们都拥有 生产产品 这一职责。

  • 工厂方法模式:让单一产品线上的产品更易被扩展
  • 抽象工厂模式:让多条 {单一产品线上的产品更易被扩展} 的同时,能够让多条线上的产品保持约束

工厂方法&抽象工厂

如上图,横向有两条产品线(手机、电脑),纵向有三个产品簇(苹果、三星、小米)。当我们不需要考虑产品簇时,为工厂方法模式。反之,就是抽象工厂模式。


怎么来实现抽象工厂模式

目录

可以发现在目录层级上与工厂方法模式并没有区别,差异在工厂的组织形式上。

先定义产品接口

代码语言:javascript
复制
public interface IPhone {

    void screen();

    void micro();

    void battery();

    void usb();

    // XXX just for test
    void printLog();
}

产品实现类

苹果手机,及电脑的实现类就省略了。

代码语言:javascript
复制
public class XiaoMiPhoneImpl implements IPhone {
    private String TAG = "小米手机";

    @Override
    public void screen() {
        System.out.println(TAG + "屏幕");
    }

    @Override
    public void micro() {
        System.out.println(TAG + "麦克风");
    }

    @Override
    public void battery() {
        System.out.println(TAG + "电池");
    }

    @Override
    public void usb() {
        System.out.println(TAG + "usb插口");
    }

    @Override
    public void printLog() {
        screen();
        micro();
        battery();
        usb();
    }

}

定义工厂接口

实际生活中可能无法提取工厂接口,毕竟每个工厂生产的产品不可能都保持一致。在这里定义接口的目的是想强调:这是纵向的产品簇。

代码语言:javascript
复制
public interface IFactory {

    void createPhone();

    void createComputer();
}

定义小米工厂

代码语言:javascript
复制
public class XiaoMiFactoryImpl implements IFactory {
    @Override
    public void createPhone() {
        IPhone phone = new XiaoMiPhoneImpl();
        phone.printLog();
    }

    @Override
    public void createComputer() {
        IComputer computer = new XiaoMiComputerImpl();
        computer.printLog();
    }
}

客户端调用测试

代码语言:javascript
复制
public class Client {

    public static void main(String[] args) {

        IFactory factory = new XiaoMiFactoryImpl();
        factory.createPhone();
        factory.createComputer();

    }
}

测试结果

代码语言:javascript
复制
小米手机屏幕
小米手机麦克风
小米手机电池
小米手机usb插口
小米电脑屏幕
小米电脑键盘
小米电脑鼠标
小米电脑usb

在理解了思想的前提下,编写这些代码是相当简单的。

抽象工厂模式在Android源码中的应用

IPolicy 是产生窗口屏幕相关对象的抽象接口,在 android 源码中,Policy 是 IPolicy 的唯一一个实现,用于生成对象集合。Policy 创建了一系列的对象(PhoneWindow、PhoneLayoutInflater、PhoneWindowManager、PhoneFallbackEventHandler)。从UML图就可以看出,IPolicy算是一个典型的抽象工厂,只不过在源码中只有一个具体的工厂实现。

另外Policy的实现还有一点特殊的地方,它使用static域将他需要创建的对象都预先load出来,也就是说当虚拟机加载Policy类的时候,就会加载它创建的对象的class。

定义工厂接口

代码语言:javascript
复制
public interface IPolicy {
    public Window makeNewWindow(Context context);

    public LayoutInflater makeNewLayoutInflater(Context context);

    public WindowManagerPolicy makeNewWindowManager();

    public FallbackEventHandler makeNewFallbackEventHandler(Context context);
}

定义工厂实现类

代码语言:javascript
复制
public class Policy implements IPolicy {
    private static final String TAG = "PhonePolicy";

    private static final String[] preload_classes = {
        "com.android.internal.policy.impl.PhoneLayoutInflater",
        "com.android.internal.policy.impl.PhoneWindow",
        "com.android.internal.policy.impl.PhoneWindow$1",
        "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
        "com.android.internal.policy.impl.PhoneWindow$DecorView",
        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
    };

    static {
        // For performance reasons, preload some policy specific classes when
        // the policy gets loaded.
        for (String s : preload_classes) {
            try {
                Class.forName(s);
            } catch (ClassNotFoundException ex) {
                Log.e(TAG, "Could not preload class for phone policy: " + s);
            }
        }
    }

    public Window makeNewWindow(Context context) {
        return new PhoneWindow(context);
    }

    public LayoutInflater makeNewLayoutInflater(Context context) {
        return new PhoneLayoutInflater(context);
    }

    public WindowManagerPolicy makeNewWindowManager() {
        return new PhoneWindowManager();
    }

    public FallbackEventHandler makeNewFallbackEventHandler(Context context) {
        return new PhoneFallbackEventHandler(context);
    }
}

定义产品类 (Window

代码太多,咱就不贴了。

定义产品实现类(PhoneWindow

代码太多,咱就不贴了。

为什么不用4个单独的工厂(工厂方法模式)去实现呢?

其实四种不同的产品(Window,WindowManagerPolicy,LayoutInflater,FallbackEventHandler),如果用四个工厂方法也是可以的,但是会缺乏将本来应该有相互关联的产品拆分开了,抽象工厂一定程度上提高了它们之间的内聚。

假如除了Phone外,如果需要加入新的产品簇(比如说TV,智能手表),那么只需要创建一个对应Policy,以及对应的产品系列,然后将PolicyManager的IPolicy指向新产品簇的Policy就好了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.03.30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 回顾众多工厂模式
    • 简单工厂模式
      • 工厂方法模式
      • 抽象工厂模式的理念
      • 抽象工厂模式与工厂方法模式的差异
      • 怎么来实现抽象工厂模式
        • 先定义产品接口
          • 产品实现类
            • 定义工厂接口
              • 定义小米工厂
                • 客户端调用测试
                  • 测试结果
                    • 定义工厂接口
                    • 定义工厂实现类
                    • 定义产品类 (Window)
                    • 定义产品实现类(PhoneWindow)
                    • 为什么不用4个单独的工厂(工厂方法模式)去实现呢?
                • 抽象工厂模式在Android源码中的应用
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档