设计模式之抽象工厂模式

抽象工厂模式

先看问题:

现在需要为一个设置程序设计皮肤,皮肤需要能够修改所有的TextBoxButton的样式。

分析问题:

第一:虽然皮肤不同,但是所支持的操作需要是相同的,因此需要设计TextBoxButton接口

第二:需要便于切换。

因此,可以写出以下代码:

  • 创建ButtonTextBox接口
    //按钮接口
    public interface Button {
     void click();
    }
    //文本框接口
    public interface TextBox {
      void write();
    }
    
    
  • 实现不同的皮肤
    //蓝色皮肤
    public class BlueButton implements Button {
      @Override
      public void click() {
          System.out.println("蓝色按钮样式");
      }
    }
    
    public class BlueTextBox implements TextBox {
      @Override
      public void write() {
          System.out.println("蓝色文本框样式");
      }
    }
    
    
    //绿色皮肤
    public class GreenButton implements Button {
      @Override
      public void click() {
          System.out.println("绿色按钮样式");
      }
    }
    
    public class GreenTextBox implements TextBox {
      @Override
      public void write() {
          System.out.println("绿色文本框样式");
      }
    }
    
    
  • 设置配置文件
    public class SkinConf {
       //可以通过修改此配置来修改皮肤
      public  static final  String COLOR="Green";
    }
    
    
  • 创建对应的工厂,方便根据配置切换皮肤
    public class ButtonFactory {
      public static Button createButton() {
          switch (SkinConf.COLOR) {
              case "Green":
                  return new GreenButton();
              case "Blue":
                  return new BlueButton();
              default:
                  throw new UnsupportedOperationException("没有此皮肤");
          }
      }
    }
    
    
    public class TextBoxFactory {
      public static TextBox createTextBox() {
          switch (SkinConf.COLOR) {
              case "Green":
                  return new GreenTextBox();
              case "Blue":
                  return new BlueTextBox();
              default:
                  throw new UnsupportedOperationException("没有此皮肤");
          }
      }
    }
    
    
  • 使用方式如下
    public class Main {
      public static void main(String[] args) {
          TextBox textBox =TextBoxFactory.createTextBox();
          Button button =ButtonFactory.createButton();
    
          textBox.write();
          button.click();
      }
    }
    

可以看到,我们通过简单工厂,基本实现了通过修改SKIN字段即可修改全局所有的按钮和文本框样式

这基本实现了所需要的功能,但是,随着所需要定制皮肤的组件越来越多,每增加一个组件比如ImageBox,就需要增加一个工厂,这样会导致小类越来越多。并且当需要增加新的皮肤的时候,需要修改所有的工厂,不符合开闭原则

通过思考我们可以发现,同一款皮肤的是紧密相连的,比如所有的绿色主题的组件,他们有个共同点就是皮肤都是以绿色为主题的,那么,我们可以不为每个控件设置一个工厂类,而是以皮肤为界限,设置工厂类。

修改上面的代码如下:

//蓝色皮肤工厂
public class BlueFactory implements Factory{
    @Override
    public TextBox getTextBox(){
       return new BlueTextBox();
    }

    @Override
    public Button getButton(){
        return new BlueButton();
    }
}

//绿色皮肤工厂
public class GreenFactory implements  Factory {
    @Override
    public TextBox getTextBox() {
        return new GreenTextBox();
    }

    @Override
    public Button getButton() {
        return new GreenButton();
    }
}
public class Main {

    public static void main(String[] args) {
        //同样可以配置一个全局单例的Factory,这里不再赘述
        Factory factory=new GreenFactory();

        TextBox textBox = factory.getTextBox();
        Button button =factory.getButton();

        textBox.write();
        button.click();
    }
}

可以看到,当我们需要增加组件的时候,只需要在对应的工厂中添加对应新的组件即可。

这便是抽象工厂模式

以上示例代码均在:https://github.com/dengchengchao/design-pattern

抽象工厂

定义:提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象

本质:提供接口,创建一系列相关或独立的对象,而不指定这些对象的具体类

可以从上面的例子看出:抽象工厂和工厂方法的区别在于抽象工厂中每个工厂是创建一系列的产品,而工厂方法是每个工厂只创建一个产品。

UML

image

UML图如上,可以看出来,AbstractFactory负责对外提供接口,用于创建同一产品簇的各个产品,而每个产品类都有对应的接口。

优点

  • 能够从多个产品簇的多个产品中,简单的获取想要的一系列产品。
  • 属于创造类的设计模式,能够将对象的创建于使用分离开来。
  • 增加新的产品簇的时候,比较方便,且符合“开闭原则”

缺点

  • 具有开闭原则的“倾斜性”,当需要增加新的产品结构的时候,比如上面的例子中,需要增加一个ImageBox组件的时候,需要修改原本的代码,不符合开闭原则

通过上面的例子我们可以发现,使用工厂方法的时候,可以很方便的增加一个ImageBox组件,但是在增加新的产品簇:比如红色的皮肤的时候,需要修改所有的工厂,因此需要更具具体的情况来选择。

应用场景

  • 某个系统中,拥有统一的一系列产品,并且此产品需要统一产生,属于同一个产品族的产品将在一起使用
  • 系统中有多于一个的产品族,而每次只使用其中某一产品族
  • 产品簇频繁扩展,而产品类型比较稳定

尊重劳动成果,转载注明出处