抽象工厂模式和建造者模式
1.抽象工厂模式:
背景:工厂方法模式针对于每种具体产品都有对应的工厂。
目的:一个工厂可以提供多个产品对象,而不是单一的产品对象,减少工厂的数量。
原因:在产品族和产品结构构成的二维结构示意图中,使用工厂方法意味着需要n*m个工厂(假设产品族有n种产品,产品结构有m个族),但是使用抽象工厂模式仅需m个工厂,大大减少了具体工厂类。
1.1.如何使用抽象工厂模式?
回答:
1.抽象工厂接口,里面应有n种产品的创建方法声明,数量:一个。
2.针对抽象工厂接口根据不同产品族需求实现同产品结构不同的族实现,产物:具体工厂,数量:多个。
3.提取出每种具体产品的共性,写成有实现但非空实现的非抽象方法(普通方法,共性体现在普通),以及一些留给具体产品依据不同族同行为的不同实现,当然,也可以在具体产品中有特性,产物:抽象产品,数量:一个。
4.继承抽象产品,保留共性,实现不同族同行为的不同实现(可额外添加特性),产物:具体产品,数量:多个。
模式结构:
1.2.模式分析:
抽象工厂类的典型代码如下:
public abstract class AbstractFactory
{
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}
具体工厂类的典型代码如下:
public class ConcreteFactory1 extends AbstractFactory
{
public AbstractProductA createProductA()
{
return new ConcreteProductA1();
}
public AbstractProductB createProductB()
{
return new ConcreteProductB1();
}
}
1.3.模式实例与解析
实例一:电器工厂
一个电器工厂可以产生多种类型的电器,如海尔工厂可以生产海尔电视机、海尔空调等,TCL工厂可以生产TCL电视机、TCL空调等,相同品牌的电器构成一个产品族,而相同类型的电器构成了一个产品等级结构,现使用抽象工厂模式模拟该场景。
1.4.模式优缺点
1.4.1.抽象工厂模式的优点
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
- 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
1.4.2.抽象工厂模式的缺点
- 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
- 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)
2.建造者模式:
背景:通过塑造部分来创建整体。
目的:同部分的不同的塑造实现创建不同整体。
原因:部分的塑造过程客户端不可见的同时能得到不同整体。
2.1.如何使用建造者模式?
抽象建造者:塑造各部分的方法,返回塑造的对象(整体),数量:一个
具体建造者:继承自抽象建造者,根据不同塑造需求实现塑造各部分的方法,实现返回对应塑造的对象(整体),数量:多个。
产品:被构建的复杂对象,也可以是抽象产品,多个具体产品继承。
指挥者:又称导演类,拥有能够调用具体建造者中塑造部分的方法,这就意味着要组合抽象建造者,同时还要通过建造者调用返回对象的方法,一般书上都是以construct方法来表现的,根据不同的对象可以定义不同的construct方法,如constructA,constructB…
2.2.模式结构
2.3.模式分析
一个典型的复杂对象其类代码示例如下:
public class Product
{
private String partA; //可以是任意类型
private String partB;
private String partC;
//partA的Getter方法和Setter方法省略
//partB的Getter方法和Setter方法省略
//partC的Getter方法和Setter方法省略
}
抽象建造者类中定义了产品的创建方法和返回方法,其典型代码如下:
public abstract class Builder
{
protected Product product=new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
public Product getResult()
{
return product;
}
}
指挥者类的代码示例如下:
public class Director
{
private Builder builder;
public Director(Builder builder)
{
this.builder=builder;
}
public void setBuilder(Builder builder)
{
this.builder=builer;
}
public Product construct()
{
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}
客户端类代码片段:
……
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();
……
2.4.模式优缺点
2.4.1.建造者模式的优点
- 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。
- 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
- 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。
2.4.2.建造者模式的缺点如下:
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
模式应用
在很多游戏软件中,地图包括天空、地面、背景等组成部分,人物角色包括人体、服装、装备等组成部分,可以使用建造者模式对其进行设计,通过不同的具体建造者创建不同类型的地图或人物。
2.5.建造者模式与抽象工厂模式的比较
- 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族。
- 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象。
- 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。