设计模式[创建型]03--抽象工厂模式(Abstract Factory)

一、简介

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

注意:这里和工厂方法的区别是:一系列(多个),而工厂方法只有一个。

二、类结构

抽象工厂模式结构如下:

角色 类别 简述
AbstractFactory 抽象工厂 一般是一个抽象类或是接口
ConcreteFactory 具体工厂 用来创建一系列具体的产品
AbstractProduct 抽象产品 一个抽象类或是接口
Product 具体产品 用来创建具体的产品

三、UML图

比如,我们需要设计一个绘图工具:

四、代码分析

1、抽象产品

图形类接口:

interface Shape{
    public function draw();
}

颜色类接口:

interface Color {
   public function fill();
}

2、具体产品

具体图形类:

//矩形类
class Rectangle implements Shape {
    public function draw() {
        echo '插入一个矩形 \n\r';
    }
}
//正方形类
class Square implements Shape {
    public function draw() {
        echo '插入一个正方形 \n\r';
    }
}
//圆形类
class Circle implements Shape {
    public function draw() {
        echo '插入一个圆形 \n\r';
    }
}

具体颜色类:

//红色类
class Red implements Color {
    public function fill() {
        echo '填充红色 \n\r';
    }
}
//绿色类
class Green implements Color {
    public function fill() {
        echo '填充绿色 \n\r';
    }
}
//蓝色类
class Blue implements Color {
    public function fill() {
        echo '填充蓝色 \n\r';
    }
}

3、抽象工厂

为 Color 和 Shape 对象创建抽象类来获取工厂。

class interface AbstractFactory {
   public function getColor($color);
   public function getShape($shape) ;
}

4、具体工厂

//形状工厂类
class ShapeFactory extends AbstractFactory {

    public function getShape($shapeType){
        if($shapeType == false){
            return false;
        }        
        if($shapeType=="circle"){
            return new Circle();
        } else if($shapeType=="rectangle"){
            return new Rectangle();
        } else if($shapeType=="square"){
            return new Square();
        }
        return false;
    }
    
    public function getColor($color) {
        return false;
    }
}

//颜色工厂类
class ColorFactory extends AbstractFactory {

    public function getShape($shapeType){
        return false;
    }
   
    public function getColor($color) {
        if($color == false){
            return false;
        }
        if($color=="red"){
            return new Red();
        } else if($color=="green"){
            return new Green();
        } else if($color=="blue"){
            return new Blue();
        }
        return false;
    }
}

5、工厂创造器

创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。

class FactoryProducer {
    public static function getFactory($choice){
        if($choice=="shape")){
            return new ShapeFactory();
        } else if($choice=="color"){
            return new ColorFactory();
        }
        return null;
    }
}

6、使用实例

public class Demo {
   public static function test() {
 
      //获取形状工厂
      $shapeFactory = FactoryProducer::getFactory("SHAPE");
      
      //为形状插入Circle对象
      $shape1 = $shapeFactory->getShape("circle");
      //调用 Circle 的 draw 方法
      $shape1->draw();
 
      //为形状插入Rectangle对象
      $shape2 = $shapeFactory->getShape("rectangle");
      //调用 Rectangle 的 draw 方法
      $shape2->draw();
      
      //获取颜色工厂
      $colorFactory = FactoryProducer::getFactory("color");
 
      //获取颜色为 Red 的对象
      $color1 = $colorFactory->getColor("red");
      //调用 Red 的 fill 方法
      $color1->fill();
   }
}

Demo::test();

测试结果:

插入一个圆形
插入一个矩形
填充红色

五、特点

1、优点

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

2、缺点

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

3、适用场景

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

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