创建型模式:抽象工厂模式(Abstract Factory Pattern)

时间:2022-09-08 20:14:44

经过很多大神的总结,目前Java中一共23种经典的设计模式

按照目的,设计模式可以分为以下三种用途:

1.创建型模式:用来处理对象的创建过程

2.结构型模式: 用来处理类或者对象的组合

3.行为型模式:用来对类或对象怎样交互和怎样分配职责进行描述


创建型模式用来处理对象的创建过程,主要包含以下5种设计模式:
 工厂方法模式(Factory Method Pattern)
 抽象工厂模式(Abstract Factory Pattern)
 建造者模式(Builder Pattern)
 原型模式(Prototype Pattern)

 单例模式(Singleton Pattern)


结构型模式用来处理类或者对象的组合,主要包含以下7种设计模式:
 适配器模式(Adapter Pattern)
 桥接模式(Bridge Pattern)
 组合模式(Composite Pattern)
 装饰者模式(Decorator Pattern)
 外观模式(Facade Pattern)
 享元模式(Flyweight Pattern)

 代理模式(Proxy Pattern)


行为型模式用来对类或对象怎样交互和怎样分配职责进行描述,主要包含以下11种设计模式:
 责任链模式(Chain of Responsibility Pattern)
 命令模式(Command Pattern)
 解释器模式(Interpreter Pattern)
 迭代器模式(Iterator Pattern)
 中介者模式(Mediator Pattern)
 备忘录模式(Memento Pattern)
 观察者模式(Observer Pattern)
 状态模式(State Pattern)
 策略模式(Strategy Pattern)
 模板方法模式(Template Method Pattern)

 访问者模式(Visitor Pattern) 

本篇文章主要为讲解一下抽象工厂模式(Abstract Factory Pattern)

一、抽象工厂模式概念
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据LSP原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。


二、抽象工厂模式定义

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类

类图

创建型模式:抽象工厂模式(Abstract Factory Pattern)


三、抽象工厂模式简介

当每个抽象产品都有多于一个的具体子类的时候,工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产[1] 品角色都有两个具体产品。抽象工厂模式提供两个具体工厂角色,分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化。每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。

每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结构。


四、抽象工厂模式与工厂方法模式的区别:

        抽象工厂模式是工厂方法模式的升级版本,它用来创建一组相关或者相互依赖的对象。

它与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类
       
在抽象工厂模式中,有一个产品族的概念:

产品族是指位于不同产品等级结构中,功能相关联的产品组成的家族。一般是位于不同的等级结构中的相同位置上。显然,每一个产品族中含有产品的数目,

与产品等级结构的数目是相等的,形成一个二维的坐标系,水平坐标是产品等级结构,纵坐标是产品族。总称:相图。

当有多个不同的等级结构的产品时,如果使用工厂方法模式就势必要使用多个独立的工厂等级结构来对付这些产品的等级结构。如果这些产品等级结构是平行的,

会导致多个平行的工厂等级结构。

抽象工厂模式使用同一个 工厂等级结构负责这些不同产品等级结构产品对象的创建。

对于每一个产品族,都有一个具体工厂。而每一个具体工厂创建属于同一个产品族,但是分属于不同等级结构的产品。
通过引进抽象工厂模式,可以处理具有相同(或者相似)等级结构的多个产品族中的产品对象的创建问题。
由于每个具体工厂角色都需要负责两个不同等级结构的产品对象的创建,因此每个工厂角色都需要提供两个工厂方法,分别用于创建两个等级结构的产品。

既然每个具体工厂角色都需要实现这两个工厂方法,所以具有一般性,不妨抽象出来,移动到抽象工厂角色中加以声明。

抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。

我们依然拿生产汽车的例子来说明他们之间的区别:

创建型模式:抽象工厂模式(Abstract Factory Pattern)

在上面的类图中,两厢车和三厢车称为两个不同的等级结构;而2.0排量车和2.4排量车则称为两个不同的产品族。再具体一点,2.0排量两厢车和2.4排量两厢车属于同一个等级结构,2.0排量三厢车和2.4排量三厢车属于另一个等级结构;而2.0排量两厢车和2.0排量三厢车属于同一个产品族,2.4排量两厢车和2.4排量三厢车属于另一个产品族

 明白了等级结构和产品族的概念,就理解工厂方法模式和抽象工厂模式的区别了,如果工厂的产品全部属于同一个等级结构,则属于工厂方法模式;如果工厂的产品来自多个等级结构,则属于抽象工厂模式。

五、实例一:农场系统
在农场系统的实现
//两种抽象产品:水果、蔬菜
public interface Fruit{}
public interface Veggie{}
//四种具体产品:北方水果,热带水果,北方蔬菜,热带蔬菜
//Northern Fruit
public class NorthernFruit implements Fruit{
private String name;
public NorthernFruit(String name){}
public String getName(){
return name;
}
public void setName(String name){
this. name = name;
}
}
//TropicalFruit
public class TropicalFruit implements Fruit{
private String name;
public TropicalFruit(String name){}
public String getName(){
return name;
}
public void setName(String name){
this. name = name;
}
}
//NorthernVeggie
public class NorthernVeggie implements Veggie{
private String name;
public NorthernVeggie(String name){}
public String getName(){
return name;
}
public void setName(String name){
this. name = name;
}
}
//TropicalVeggie
public class TropicalVeggie implements Veggie{
private String name;
public TropicalVeggie(String name){}
public String getName(){
return name;
}
public void setName(String name){
this. name = name;
}
}
//抽象工厂角色
public interface Gardener{
public Fruit createFruit(String name);
public Veggie createVeggie(String name);
}
//具体工厂角色:北方工厂,热带角色
public class NorthernGardener implements Gardener{
public Fruit createFruit(String name){
return new NorthernFruit(name);
}
public Veggie createVeggie(String name){
return new NorthernVeggie(name);
}
}
public class TropicalGardener implements Gardener{
public Fruit createFruit(String name){
return new TropicalFruit(name);
}
public Veggie createVeggie(String name){
return new TropicalVeggie(name);
}
}
这样客户端只需要创建具体工厂的实例,然后调用工厂对象的工厂方法就可以得到所需要的产品对象。

六、实例二:微型计算机配件


这个系统所需要的产品族有两个,一个系列是PC系列,另一个系列是MAC系列。

产品等级结构也有两个,一个是RAM,一个是CPU。

//两个抽象产品

public interface Cpu{}

public interface Ram{}

//四个具体产品

public class PcCpu implements Cpu{}

public class MacCpu implements Cpu{}

public class PcRam implements Ram{}

public class MacRam implements Ram{}
//抽象工厂角色

public interface ComputerProducer{

Cpu createCpu();

Ram createRam();

}

//两个具体工厂角色

public class PcProducer implements ComputerProducer{

public Cpu createCpu(){

return new PcCpu();

}

public Ram createRam(){

return new PcRam();

}

}


public class MacProducer implements ComputerProducer{

public Cpu createCpu(){

return new MacCpu();

}

public Ram createRam(){

return new MacRam();

}

}

一般情况下,有多少个抽象产品,就有多少个工厂方法。(比如再增加一个PC与MAC不同的其他计算机配件,例如显卡)。

OCP(开放-封闭原则(The Open-Close Principle,简称OCP))

增加产品族。

增加产品等级结构。

在不改变产品等级结构的情况下,增加产品族就是意味着向每一个产品等级结构中增加一个或者多个新的具体产品角色,这时只需要向工厂等级结构中增加新的元素就可以了,具体的说,只需要增加新的具体工厂类就可以了。


在产品族数目不变的情况下,增加产品等级结构,相当于增加一个与现有产品等级结构平行的一个新的产品等级结构,这时需要向修改所有的工厂角色,

增加一个新的工厂方法,这是不支持OCP的。

Producer

PcProducer MacProducer

CPU

PcCPU MacCPURAM

PcRAM MacCPU

在上面的结构中,增加产品族相当于增加一个新的厂商,比如Sun的CPU和RAM,这时,只需要增加一个SunProducer即可。

而增加一个新的产品等级结构相当于增加一个显卡,而显卡也有Pc和Mac之分,那么对于所有的Producer,都需要增加一个方法:createCard()


七、优缺点

优点;抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。

1.它分离了具体的类
2.它使得易于交换产品系列
3.它有利于产品的一致性

缺点:产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。

1.难以支持新种类的产品


八、适用场景:
       当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。

说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。

假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。
工厂方法模式:
(1) 当一个类不知道它所必须创建的对象的类的时候。
(2) 当一个类希望由它的子类来指定它所创建的对象的时候。
(3) 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
抽象工厂模式:
(1) 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
(2) 这个系统有多于一个的产品族,而系统只消费其中某一产品族。
(3) 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
(4) 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。


九、总结:

       无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。
       所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。


创建型模式:抽象工厂模式(Abstract Factory Pattern)