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

来源:互联网 发布:js添加dom 编辑:程序博客网 时间:2024/05/17 23:20

模式动机

       在工厂模式中,具体工厂负责生产具体的产品,每一个具体工厂对应一种具体的产品,但有的时候,我们需要一个工厂可以生产多种产品。为了阐述的更加清晰明了,首先引入两个抽象工厂模式中概念:产品等级结构和产品族

  • 产品等级结构
    比如一个抽象类是电视机,其子类有长虹电视机,创维电视机,TCL电视机,那么电视机抽象类与与具体的某个电视机子类便构成了一个产品等级结构,抽象电视机是父类,具体某个品牌的电视机是子类。简单通俗的来讲,可以理解为同一个产品等级结构,就代表同一类产品,比如电视机可以构成一个产品等级,洗衣机是一个产品等级,电冰箱也是一个产品等级等等

  • 产品族
    在抽象工厂模式中,产品族是指同一个工厂生产的、且属于不同产品等级结构的一组产品。打个比方,假如有一个创维电器工厂,里面可以生产创维电视机,创维洗衣机等等,由于电视机跟洗衣机是不同的产品等级,所以整个创维系列的产品构成了一个产品族。

    总结:产品等级结构可以理解为同一种分类,不同品牌的产品,而产品族可以理解为同一种品牌、不同分类的产品。如下图:
    产品等级和产品族
    在上一篇博客《设计模式-创建型之工厂模式 》中,我们的工厂类只对应了一个产品,如BenzCarFactory负责生产BenzCar,BMWCarFactory负责生产BMWCar。但在现实生活中,奔驰跟宝马不仅生产轿车,它们其实也生产自行车。套入刚才的概念可知,轿车跟自行车属于不同的产品等级结构,而奔驰、宝马属于不同的产品族。假设这样一种情况,现在我们需要构建一个奔驰工厂,里面既可以生产奔驰汽车,也可以生产奔驰自行车,还有一个宝马工厂,里面既可以生产宝马汽车,也可以生产宝马自行车。这便是我们的抽象工厂模式!

模式定义

       提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类,抽象工厂模式也叫Kit模式。其实也很简单,就是在工厂模式的基础上进行了增强,让其更加具有通用性,一般性。工厂模式中工厂类只负责一种产品的创建工作,在抽象工厂模式中,一个工厂可以生产多种产品,这些产品都属于同一个产品族。

模式结构

模式结构
       工厂模式主要由以下四部分组成:
  抽象工厂:抽象出工厂所需属性或行为,如IFactory
  具体工厂:具体的某个工厂类,负责创建某个具体的产品,如BenzFactory,BMWFactory
  抽象产品:抽象出产品所需属性或行为,ICar,IBike
  具体产品:具体的某个产品,如BenzCar,BMWCar,BenzBike,BMWBike

代码实现

抽象工厂类

public interface IFactory {    public abstract ICar createCar();    public abstract IBike createBike();}

  具体工厂类

public class BenzFactory implements IFactory{    @Override    public ICar createCar() {        return new BenzCar();    }    @Override    public IBike createBike() {        return new BenzBike();    }}
public class BMWFactory implements IFactory{    @Override    public ICar createCar() {        return new BMWCar();    }    @Override    public IBike createBike() {        return new BMWBike();    }}

  抽象产品类

public interface ICar {    public abstract String getName();}
public interface IBike {    public abstract String getName();}

  具体产品类

public class BMWBike implements IBike {    @Override    public String getName() {        return "宝马Bike";    }}
public class BMWCar implements ICar {    @Override    public String getName() {        return "宝马Car";    }}
public class BenzBike implements IBike {    @Override    public String getName() {        return "奔驰Bike";    }}
public class BenzCar implements ICar {    @Override    public String getName() {        return "奔驰Car";    }}

  客户端测试类

public class Client {    public static void main(String[] args) {        IFactory factory1 = new BenzFactory();        IFactory factory2 = new BMWFactory();        ICar car1 = factory1.createCar();        IBike bike1 = factory1.createBike();        ICar car2 = factory2.createCar();        IBike bike2 = factory2.createBike();        System.out.println(car1.getName());        System.out.println(bike1.getName());        System.out.println(car2.getName());        System.out.println(bike2.getName());    }}

  运行客户端测试类,输出为

奔驰Car奔驰Bike宝马Car宝马Bike

模式优缺点

优点

  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,因为所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。比如我们的例子中,如果想把生产奔驰这个产品系列修改为生产宝马系列。那么只需要将IFactory factory1 = new BenzFactory()修改为IFactory factory1 = new BMWFactory()即可。这里我们只是方便测试,写得很简单。在实际开发中,完全可以将我们的工厂配置在xml、property等配置文件中,然后通过java的反射机制对具体工厂进行实例化,所以我们只需要修改一下配置文件,就可以达到修改整个产品系列的效果
  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象
  • 增加新的产品族很方便,只需要新增相应的具体工厂类和具体产品类即可。比如现在我们需要新增一个奥迪工厂,用于生产奥迪汽车和奥迪自行车,则只需要新增AudiFactory,AudiCar,AudiBike即可,无需修改之前的代码。

缺点

  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。比如在我们的例子中,现在需要新增一个“摩托车”产品。那么我们则需要修改IFactory,添加createMotorcycle()方法,BMWFactory跟BenzFactory也需要增加该方法。这样显然是改动很大的。

开闭原则的倾斜性

       根据抽象模式的优缺点可以看出,增加产品族是无需修改已有代码的,很好的支持了开闭原则,但新增新的产品等级结构时,则需要修改抽象工厂类及其子类,违背了开闭原则。抽象工厂模式这种性质我们成为“开闭原则的倾斜性”

适用场景

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

总结

       抽象工厂模式稍微要比工厂模式复杂一些,但其实也复杂不了多少。简单理解下,无非就是工厂模式中的工厂只生产一种产品,而抽象工厂模式中的工厂是生产多个产品,即一个产品族。

0 0