悟空模式-java-抽象工厂模式

【一朝,王母娘娘设宴,大开宝阁,瑶池中做蟠桃胜会】

有一天,王母娘娘要在瑶池办party,就需要准备大量的食材。要知道,天上的神仙也分三六九等,九曜星、五方将、二十八宿、四大天王、十二元辰、五方五老、普天星相、河汉群神等等,不同等级的神仙在宴会中吃的东西也不一样。

为了方便管理,我们把神仙分为低级神仙、中级神仙和高级神仙,不同等级的神仙将领取到对应等级的食物,所以就有了低级神仙食物、中级神仙食物和高级神仙食物。

在前面的悟空模式-java-普通工厂模式悟空模式-java-工厂方法模式中都介绍了低级蟠桃(三千年)、中级蟠桃(六千年)和高级蟠桃(九千年),虽然是蟠桃盛会,但也总不能光吃蟠桃,所以由兜率宫拿出了一批仙丹,分为低级仙丹(炼三三得九天)、中级仙丹(炼七七四十九天)和高级仙丹(炼九九八十一天)。

以上,就是我们本次演示抽象工厂模式所需要的产品元素。

在前面我们说过,当产品越来越多,会使得工厂越来越难管理,要么工厂的数量越来越多,要么工厂本身越来越复杂,所以,这里介绍了抽象工厂模式,用于产生较为复杂的产品结构下的工厂,它与工厂方法最基本的区别是抽象工厂模式能够创建不同种类的产品,也就能够更加方便地基于抽象的概念管理一大堆复杂的产品对象。

首先我们介绍两个概念:产品族与产品等级。

所谓产品族,就是由功能相关联的不同种类产品组成的家族,比如我们最终所需要的低级神仙食物,它是由低级蟠桃与低级仙丹组成的。而产品等级就是对于某一种类的产品,内部划分的等级结构,如蟠桃内部被划分为低级、中级与高级,产品等级是面向同一种类的产品的内部区别描述。

在一开始,我们需要创建一个抽象工厂,这个抽象工厂中描述了每个具体工厂需要提供哪些实现。然后针对每一个产品族创建一个工厂,用于统一创建不同类型的产品。类图如下:

从图中可以看到,不同等级的产品交给了不同的工厂去创建,用户只需要调用自己的目标产品族对应的工厂,获取最终的产品族即可,至于这个产品系列内部结构如何变化,用户并不需要关心。接下来是具体的实现:

蟠桃

package com.tirion.design.abstraction.factory;

public interface FlatPeach {

    void printLevel();

    void printCycleTime();
}

低级蟠桃

package com.tirion.design.abstraction.factory;

public class LowLevelFlatPeach implements FlatPeach {

    LowLevelFlatPeach(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("低级蟠桃");
    }

    @Override
    public void printCycleTime() {
        System.out.println("三千年一熟");
    }

}

中级蟠桃

package com.tirion.design.abstraction.factory;

public class MiddleLevelFlatPeach implements FlatPeach {

    MiddleLevelFlatPeach(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("中级蟠桃");
    }

    @Override
    public void printCycleTime() {
        System.out.println("六千年一熟");
    }

}

高级蟠桃

package com.tirion.design.abstraction.factory;

public class HighLevelFlatPeach implements FlatPeach {

    HighLevelFlatPeach(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("高级蟠桃");
    }

    @Override
    public void printCycleTime() {
        System.out.println("九千年一熟");
    }

}

仙丹

package com.tirion.design.abstraction.factory;

public interface Elixir {

    void printLevel();

    void printCycleTime();
}

低级仙丹

package com.tirion.design.abstraction.factory;

public class LowLevelElixir implements Elixir {

    LowLevelElixir(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("低级仙丹");
    }

    @Override
    public void printCycleTime() {
        System.out.println("炼三三得九天");
    }

}

中级仙丹

package com.tirion.design.abstraction.factory;

public class MiddleLevelElixir implements Elixir {

    MiddleLevelElixir(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("中级仙丹");
    }

    @Override
    public void printCycleTime() {
        System.out.println("炼七七四十九天");
    }

}

高级仙丹

package com.tirion.design.abstraction.factory;

public class HighLevelElixir implements Elixir {

    HighLevelElixir(){
        printCycleTime();
        printLevel();
    }

    @Override
    public void printLevel() {
        System.out.println("高级仙丹");
    }

    @Override
    public void printCycleTime() {
        System.out.println("炼九九八十一天");
    }

}

抽象工厂-神仙食物工厂

package com.tirion.design.abstraction.factory;

public interface XianFoodFactory {

    FlatPeach prepareFlatPeach();

    Elixir prepareElixir();

}

低级神仙食物工厂

package com.tirion.design.abstraction.factory;

public class LowLevelXianFoodFactory implements XianFoodFactory {

    @Override
    public FlatPeach prepareFlatPeach() {
        return new LowLevelFlatPeach();
    }

    @Override
    public Elixir prepareElixir() {
        return new LowLevelElixir();
    }


}

中级神仙食物工厂

package com.tirion.design.abstraction.factory;

public class MiddleLevelXianFoodFactory implements XianFoodFactory {

    @Override
    public FlatPeach prepareFlatPeach() {
        return new MiddleLevelFlatPeach();
    }

    @Override
    public Elixir prepareElixir() {
        return new MiddleLevelElixir();
    }


}

高级神仙食物工厂

package com.tirion.design.abstraction.factory;

public class HighLevelXianFoodFactory implements XianFoodFactory {

    @Override
    public FlatPeach prepareFlatPeach() {
        return new HighLevelFlatPeach();
    }

    @Override
    public Elixir prepareElixir() {
        return new HighLevelElixir();
    }


}

王母娘娘-调用者

package com.tirion.design.abstraction.factory;


public class TheQueenMother {

    public static void prepareXianFood(XianFoodFactory xianFoodFactory) {
        xianFoodFactory.prepareFlatPeach();
        xianFoodFactory.prepareElixir();
    }

    public static void main(String[] args) {
        System.out.println("准备低级神仙食物...");
        TheQueenMother.prepareXianFood(new LowLevelXianFoodFactory());
        System.out.println("准备中级神仙食物...");
        TheQueenMother.prepareXianFood(new MiddleLevelXianFoodFactory());
        System.out.println("准备高级神仙食物...");
        TheQueenMother.prepareXianFood(new HighLevelXianFoodFactory());
    }
}

代码执行结果

准备低级神仙食物...
三千年一熟
低级蟠桃
炼三三得九天
低级仙丹
准备中级神仙食物...
六千年一熟
中级蟠桃
炼七七四十九天
中级仙丹
准备高级神仙食物...
九千年一熟
高级蟠桃
炼九九八十一天
高级仙丹

使用了抽象工厂模式之后,在面对复杂的宴会菜单对象时,王母娘娘不需要关心天宫的御厨如何搭配食物,只需要下达命令要求御厨准备不同等级的食物套餐就可以了。

每个具体工厂只需要创建自己负责的产品,这符合单一职责原则。

具体工厂返回的产品是产品的抽象而不是具体,所以符合依赖导致原则。

关于开闭原则,抽象工厂模式是一个比较典型的例子。

我们在使用中可以发现,如果要添加一个新的产品族,比如王母娘娘专享食物套餐,套餐内容是高级蟠桃,而并不需要吃仙丹(王母娘娘吃仙丹已经没啥用了),那么我们只需要增加一个TheQueenMotherFoodFactory,然后在内部添加具体的实现即可,并不需要更改其他任何类,很完美地符合了开闭原则。

王母娘娘食物工厂

package com.tirion.design.abstraction.factory;

public class TheQueenMotherFoodFactory implements XianFoodFactory {

    @Override
    public FlatPeach prepareFlatPeach() {
        return new HighLevelFlatPeach();
    }

    @Override
    public Elixir prepareElixir() {
        return null;
    }


}

但是如果某一天,镇元大仙上供了一批人参果,王母娘娘一高兴,把人参果也作为宴会的一道主菜,那么就麻烦了:不仅仅抽象工厂XianFoodFactory要增加人参果的接口,它的所有实现都要增加相应的接口实现,整个体系才能继续运转下去。这时候,抽象工厂模式又不符合开闭原则了。

根据以上描述我们可以得出,对于抽象工厂模式,增加产品族符合开闭原则,增加产品种类则不符合开闭原则,也就是说抽象工厂模式具备开闭原则的倾斜性。

注意:抽象工厂模式并不是比工厂方法模式更加高级的模式,而是为了适应不同的业务变化情况而做出的不同应对,继而产生的不同解决方案而已。

抽象工厂模式的使用情景:

1.系统中存在多个产品族,用户只关心产品族,也就是只关心最终结果

2.属于同一产品族的产品相互之间具有关联关系,它们是被组合在一起使用的

抽象工厂模式遵循的设计原则:

1.依赖倒置原则(客户端依赖的是产品抽象而不是具体产品)

2.迪米特法则

3.里氏替换原则

4.接口隔离原则(使用了多个相互隔离的接口,降低了耦合度)

5.单一职责原则(每个工厂只要负责创建自己对应产品族的产品)

6.开闭原则(具有倾斜性,支持新增产品族,但不支持新增产品类型)

关于抽象工厂模式的介绍就到这里,你可以将它记忆为蟠桃宴会模式

如果你认为文章中哪里有错误或者不足的地方,欢迎在评论区指出,也希望这篇文章对你学习java设计模式能够有所帮助。转载请注明,谢谢。

更多设计模式的介绍请到悟空模式-java设计模式中查看。

posted @ 2017-09-19 15:33  tirion0510  阅读(354)  评论(0编辑  收藏  举报