创建型模式之--抽象工厂模式

1、女娲的失误

在工厂模式中,女娲造人故事,忘记制造男女,三个肤色的人种都没有性别之分。

产品类(人)修改:
Human接口增加 getSex() 抽象方法,三种肤色的人的具体原实现类BlackHuman 、YellowHuman、WhiteHuman ,改为抽象类(不实现 getSex() 抽象方法),然后每个人种再定义各自的 FemaleXHuman和 MaleXHuman 实现类,并实现相应的 getSex() 方法。

工厂类(八卦炉)修改:
原来只有一个工厂类,要么生产男人,要么生产女人,现在需要复制一个八卦炉,分别生产男人(FemaleFactory)和女人(MaleFactory)。

类图:
这里写图片描述

代码:
人种接口:

public interface Human {
    //每个人种都有相应的颜色
    public void getColor();
    //人类会说话
    public void talk();
    //每个人都有性别
    public void getSex();
}

三种肤色人的抽象类(因为还没有性别),都实现Human接口:

public abstract class AbstractWhiteHuman implements Human {
     //白色人种的皮肤颜色是白色的
    public void getColor(){
        System.out.println("白色人种的皮肤颜色是白色的!");
    }
    //白色人种讲话
    public void talk() {
        System.out.println("白色人种会说话,一般说的都是单字节。");
    }
}
public abstract class AbstractBlackHuman implements Human {
    public void getColor(){
        System.out.println("黑色人种的皮肤颜色是黑色的!");
    }
    public void talk() {
        System.out.println("黑人会说话,一般人听不懂。");
    }
}

每个肤色的抽象类都有男性和女性两个实现类,黄色女性人种为例:

public class FemaleYellowHuman extends AbstractYellowHuman {
    //黄人女性
    public void getSex() {
        System.out.println("黄人女性");
    }
}
public class MaleYellowHuman extends AbstractYellowHuman {
    //黄人男性
    public void getSex() {
        System.out.println("黄人男性");
    }
}

工厂类接口

public interface HumanFactory {
    //制造一个黄色人种
    public Human createYellowHuman();
    //制造一个白色人种
    public Human createWhiteHuman();
    //制造一个黑色人种
    public Human createBlackHuman();
}

生产女性的工厂

public class FemaleFactory implements HumanFactory {
    //生产出黑人女性
    public Human createBlackHuman() {
        return new FemaleBlackHuman();
    }
    //生产出白人女性
    public Human createWhiteHuman() {
        return new FemaleWhiteHuman();
    }
    //生产出黄人女性
    public Human createYellowHuman() {
        return new FemaleYellowHuman();
    }
}

生产男性的工厂

public class MaleFactory implements HumanFactory {
     //生产出黑人男性
    public Human createBlackHuman() {
        return new MaleBlackHuman();
    }
    //生产出白人男性
    public Human createWhiteHuman() {
        return new MaleWhiteHuman();
    }
    //生产出黄人男性
    public Human createYellowHuman() {
        return new MaleYellowHuman();
    }
}

女娲重造人类

扫描二维码关注公众号,回复: 1464518 查看本文章
public class NvWa {
    public static void main(String[] args) {
        //第一条工厂男性工厂
        HumanFactory maleHumanFactory = new MaleFactory();
        //第二条工厂女性工厂
        HumanFactory femaleHumanFactory = new FemaleFactory();
        //开始生产人了:
        Human maleYellowHuman = maleHumanFactory.createYellowHuman();
        Human femaleYellowHuman = femaleHumanFactory.createYellowHuman();
        System.out.println("---生产一个黄色女性---");
        femaleYellowHuman.getColor();
        femaleYellowHuman.talk();
        femaleYellowHuman.getSex();
        System.out.println("\n---生产一个黄色男性---");
        maleYellowHuman.getColor();
        maleYellowHuman.talk();
        maleYellowHuman.getSex();
    }
}

2、抽象工厂类的定义

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

抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

工厂方法模式和抽象工厂模式的区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
工厂方法创建 “一种” 产品,他的着重点在于”怎么创建”,也就是说如果你开发,你的大量代码很可能
围绕着这种产品的构造,初始化这些细节上面。
抽象工厂需要创建一些列产品,着重点在于”创建哪些”产品上,也就是说,如果你开发,你的主要任务
是划分不同差异的产品线,并且尽量保持每条产品线接口一致,从而可以从同一个抽象工厂继承。

比如说工厂可以生产鼠标(A产品线)和键盘(B产品线)。(相当于女娲中的白种人和黑种人)
那么抽象工厂的实现类(它的某个具体子类)的对象都可以生产鼠标和键盘,但可能工厂 1 (女人工厂)生产的是罗技的键盘和鼠标,工厂 2 (男人工厂)生产的是微软的。

抽象工厂就像工厂,而工厂方法则像是工厂的一种产品生产线。

两个产品线的类图:
这里写图片描述

代码:
其实可以像上面女娲造人中载抽象一个产品类接口。
抽象产品类

产品线A:

public abstract class AbstractProductA {
    //每个产品共有的方法
    public void shareMethod(){
    }
    //每个产品相同方法,不同实现
    public abstract void doSomething();
}

两个具体的产品实现类
产品A1的实现类:

public class ProductA1 extends AbstractProductA {
    public void doSomething() {
        System.out.println("产品A1的实现方法");
    }
}

产品A2的实现类:

public class ProductA2 extends AbstractProductA {
    public void doSomething() {
        System.out.println("产品A2的实现方法");
    }
}

产品B与此类似,不再赘述。
一个抽象类,两个实现类。

抽象工厂类

public abstract class AbstractCreator {
    //创建A产品家族
    public abstract AbstractProductA createProductA();
    //创建B产品家族
    public abstract AbstractProductB createProductB();
}

注意 有N个产品族,在抽象工厂类中就应该有N个创建方法。

工厂1的实现类

public class Creator1 extends AbstractCreator {
    //只生产产品等级为1的A产品
    public AbstractProductA createProductA() {
        return new ProductA1();
    }
    //只生产产品等级为1的B产品
    public AbstractProductB createProductB() {
        return new ProductB1();
    }
}

工厂2的实现类

public class Creator2 extends AbstractCreator {
    //只生产产品等级为2的A产品
    public AbstractProductA createProductA() {
        return new ProductA2();
    }
    //只生产产品等级为2的B产品
    public AbstractProductB createProductB() {
        return new ProductB2();
    }
}

注意 有M个产品等级就应该有M个实现工厂类,在每个实现工厂中,实现不同产品族(线)的生产任务。

场景类:

public class Client {
    public static void main(String[] args) {
    //定义出两个工厂
    AbstractCreator creator1 = new Creator1();
    AbstractCreator creator2 = new Creator2();
    //产生A1对象
    AbstractProductA a1 = creator1.createProductA();
    //产生A2对象
    AbstractProductA a2 = creator2.createProductA();
    //产生B1对象
    AbstractProductB b1 = creator1.createProductB();
    //产生B2对象
    AbstractProductB b2 = creator2.createProductB();
    }
}

在场景类中,没有任何一个方法与实现类有关系,对于一个产品来说,我们只要知道它的工厂方法就可以直接产生一个产品对象,无须关心它的实现类。

3、抽象工厂模式的应用

优点:

  • 封装性,调用者只需关系调用接口,而不用关心产品类如何变化。
  • 是典型的解耦框架。接口和实现分离。

缺点:

  • 产品族扩展非常困难。如要增加产品 C(显示器),即产品家族由原来的2个增加到3个,抽象类中定义了可能生成的所有产品族,抽象类AbstractCreator要增加一个方法createProductC(),然后两个实现类都要修改,违反了 开闭原则。抽象类和接口是一个契约,改变契约,所有与契约有关系的代码都要修改。

注意事项:
抽象工厂模式的产品族扩展比较困难,但是一定要清楚,是产品族扩展困难,而不是产品等级。在该模式下,产品等级是非常容易扩展的,增加一个产品等级,只要增加一个工厂类负责新增加出来的产品生产任务即可。也就是说横向扩展容易,纵向扩展困难。如女娲造人中,增加制造双性人,需要为每种肤色的抽象人种类增肌一个实现类,然后再增加一个双性人工厂实现类即可,以前的代码无需修改。

最佳实践:
抽象工厂模式的起源或者最早的应用,是用于创建分属于不同操作系统的视窗构建。
比如:命令按键(Button)与文字框(Text)都是视窗构建,在UNIX操作系统的视窗环境和Windows操作系统的视窗环境中,这两个构建有不同的本地实现。Button和Text组成两个产品族。而每一个视窗构件都有自己的等级结构(不同操作系统下的实现),由一个抽象角色给出抽象的功能描述,而由具体子类给出不同操作系统下的具体实现。
UnixFactory对象负责创建Unix产品族中的产品,而WindowsFactory对象负责创建Windows产品族中的产品。在不同操作系统上运行时,只需调用相应的工厂方法。
这里写图片描述

参考资料:
【1】《设计模式之禅》-秦小波
【2】尚硅谷 java之23种设计模式解析-宋红康
【3】https://blog.csdn.net/jason0539/article/details/44976775

猜你喜欢

转载自blog.csdn.net/zxm1306192988/article/details/80467980