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

目录

  • 回顾众多工厂模式
  • 抽象工厂模式的理念
  • 抽象工厂模式与工厂方法模式的差异
  • 怎么来实现抽象工厂模式
  • 抽象工厂模式在Android源码中的应用

回顾众多工厂模式

简单工厂模式

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

简单工厂模式

工厂方法模式

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

工厂方法模式

抽象工厂模式的理念

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

抽象工厂模式

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


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

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

移动手机大卖场

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

苹果零售店

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

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

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

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


怎么来实现抽象工厂模式

目录

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

先定义产品接口

public interface IPhone {

    void screen();

    void micro();

    void battery();

    void usb();

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

产品实现类

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

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

}

定义工厂接口

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

public interface IFactory {

    void createPhone();

    void createComputer();
}

定义小米工厂

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

客户端调用测试

public class Client {

    public static void main(String[] args) {

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

    }
}

测试结果

小米手机屏幕
小米手机麦克风
小米手机电池
小米手机usb插口
小米电脑屏幕
小米电脑键盘
小米电脑鼠标
小米电脑usb

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

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

com.android.internal.policy.IPolicy

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

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

定义工厂接口

public interface IPolicy {
    public Window makeNewWindow(Context context);

    public LayoutInflater makeNewLayoutInflater(Context context);

    public WindowManagerPolicy makeNewWindowManager();

    public FallbackEventHandler makeNewFallbackEventHandler(Context context);
}

定义工厂实现类

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就好了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容