【Java设计模式】抽象工厂


✍ 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候 我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象, 这里就要引入抽象工厂的设计模式了。

为了更清晰地理解抽象工厂设计模式,需要先引入两个概念:

  • 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
  • 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的
    海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。

如果上面的文字看不太懂,也没关系,产品等级结构与产品族图示
在这里插入图片描述
相同颜色的代表同一产品等级

相同形状 不同颜色的是一个产品族

比如说华为生产基站,还生产手机,还生产芯片,华为生产的产品都是属于华为的品牌,属于同一产品等级

竖着来看 手机是方框形的 这个竖着的还有小米等手机品牌 这是同一产品组

在这里插入图片描述
向上箭头的是 一个个具体工厂

对这些概念有了解之后,会发现抽象工厂的动机很简单:

  • 当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是 多个位于不同产品等级结构中属于不同类型的具体产品时 需要使用抽象工厂模式。
  • 抽象工厂模式是所有形式的工厂模式中 最为抽象和最具一般性的一种形态 。
  • 抽象工厂模式与工厂方法模式最大的区别在于, 工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构, 一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。

✍ 这里引出抽象工厂的定义:
抽象工厂模式(Abstract Factory Pattern) : 提供一个 创建一系列相关或相互依赖对象的接口 ,而 无须指定它们具体的类 。抽象工厂模式又称为Kit 模式 ,属于 对象创建型模式

抽象工厂模式包含如下角色:

  • AbstractFactory:抽象工厂,提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
  • ConcreteFactory:具体工厂,主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  • AbstractProduct:抽象产品,定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
  • Product:具体产品,实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。

✍ 演示一下:

CakeFactory接口 (AbstractFactory:抽象工厂)

package softwareDesign.coding.factoryMethod.abstractFactory;

public interface CakeFactory {
    Cake getCake();
    GiftBox getGiftBox();
}

Cake抽象类(AbstractProduct:抽象产品)

package softwareDesign.coding.factoryMethod.abstractFactory;

public abstract class Cake {
    public abstract void produce();
}

GiftBox 抽象类(AbstractProduct:抽象产品)

package softwareDesign.coding.factoryMethod.abstractFactory;

public abstract class GiftBox {
    public abstract void produce();
}

SnowCake类(Product:具体产品)

package softwareDesign.coding.factoryMethod.abstractFactory;

public class SnowCake extends Cake{
    @Override
    public void produce() {
        System.out.println("生产雪花蛋糕...");
    }
}

SnowCakeGiftBox 类(Product:具体产品)

package softwareDesign.coding.factoryMethod.abstractFactory;

public class SnowCakeGiftBox extends GiftBox{
    @Override
    public void produce() {
        System.out.println("生产雪花蛋糕礼盒...");
    }
}

SnowCakeFactory 类(ConcreteFactory:具体工厂)

package softwareDesign.coding.factoryMethod.abstractFactory;

public class SnowCakeFactory implements CakeFactory{
    @Override
    public Cake getCake() {
        return new SnowCake();
    }

    @Override
    public GiftBox getGiftBox() {
        return new SnowCakeGiftBox();
    }
}

CCake类()(Product:具体产品)

package softwareDesign.coding.factoryMethod.abstractFactory;

public class CCake extends Cake{
    @Override
    public void produce() {
        System.out.println("生产巧克力蛋糕...");
    }
}

CCakeGiftBox类(Product:具体产品)

package softwareDesign.coding.factoryMethod.abstractFactory;

public class CCakeGiftBox extends GiftBox{
    @Override
    public void produce() {
        System.out.println("生产巧克力蛋糕礼盒");
    }
}

CCakeFactory 类(ConcreteFactory:具体工厂)

package softwareDesign.coding.factoryMethod.abstractFactory;

public class CCakeFactory implements CakeFactory {
    @Override
    public Cake getCake() {
        return new CCake();
    }

    @Override
    public GiftBox getGiftBox() {
        return new CCakeGiftBox();
    }
}

Test类

package softwareDesign.coding.factoryMethod.abstractFactory;

public class Test {
    public static void main(String[] args) {
        CakeFactory cakeFactory = new SnowCakeFactory();
        Cake cake = cakeFactory.getCake();
        GiftBox giftBox = cakeFactory.getGiftBox();
        cake.produce();
        giftBox.produce();
    }
}

我们看一下它的类图:
在这里插入图片描述
在这里插入图片描述
从CakeFactory类开始看

如果增加水果蛋糕和水果蛋糕礼盒 很容易能够拓展

加入test测试:
在这里插入图片描述
Test只关心从哪个工厂拿什么产品。应用层和具体的雪花蛋糕类及其礼盒等都是解耦的。

缺点也很明显,如果要拓展产品等级,那就违背了开闭原则,牵一发而动全身。

✍ 既然说到了缺点,就好好探究一下优缺点吧

抽象工厂模式的优点

  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

抽象工厂模式的缺点

  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品
    集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来
    较大的不便。
  • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)

✍ 在以下情况下可以使用抽象工厂模式:

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。
  • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
  • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

✍ 说一下它的应用吧:
在Java语言的AWT(抽象窗口工具包)中就使用了抽象工厂模式,它使用抽象工厂模式来实现在不同的操作系统中应用程序呈现与所在操作系统一致的外观界面。还有在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变时,可以使用抽象工厂模式进行设计。


✍ 关于抽象工厂的拓展:

“开闭原则”的倾斜性

  • “开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
  • (1) 增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
  • (2) 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。
  • 抽象工厂模式的这种性质称为“开闭原则”的倾斜性,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供这样的方便。

工厂模式的退化

  • 当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页