设计模式之三——工厂方法模式(Factory Method)&抽象工厂模式(AbstractFacotry)

时间:2022-10-01 23:22:50

模式名称

工厂方法模式(Factory Method)、抽象工厂模式(AbstractFacotry)

问题

  • 客户类不关心使用哪个具体类,只关心该接口所提供的功能。
  • 创建过程比较复杂,例如需要初始化其他关联资源,读取配置文件等。
  • 接口有很多具体实现或者抽象类有很多具体子类,避免客户端写一大堆if-else逻辑来决定运行时使用哪个具体实现或者具体子类。
  • 不希望给客户程序暴露过多此类的内部结果或创建过程,降低耦合度。
  • 优化性能,比如缓存大对象或者初始化比较耗时的对象。

GOF为工厂方法模式给出的定义:

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
为创建对象定义一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟至子类。

用法分类

实例一、简单工厂:
    //--------------参数化简单工厂创建示例--------------------------
public class ProductCreator {
Product createProduct(String type){
if(type.equals("tv")){
return new TVProduct();
}else if(type.equals("watch")){
return new WatchProduct();
}
}
}

public interface Product{}
public class TVProduct implements Product{}
public class WatchProduct implements Product{}
//---------------工厂的客户类示例----------------------------
public class Client{
private ProductCreator creator;
public Client(ProductCreator creator){
this.creator=creator;
}
public void doSomething(String type){
Product product=creator.createPorduct(type);
//to do something...
}
}
//--------------测试工厂方法---------------------------------
public class TestFacotry{
public static void main(String[] args){
Client client=new Client(new ProductCreator());
client.doSomething("car");
}
}

简单工厂并不是一个模式,只是一种习惯用法。它看起来像是把问题从一个类转移到了另一类,也就是把创建对象的行为从一个类转移到另一个类当中。但它也有其好处,例如,如果有其他客户也需要创建对象,那么就可以直接调用简单工厂,避免代码重复。

实例二、静态工厂方法

静态工厂方法同样不是一种模式,但它可以避免简单工厂类的泛滥,不需要额外的工厂类了。例如,在Java5版本里,为创建基本类型Integer、Long、Boolean对象都提供了静态工厂方法,以Integer为例:

    public static Integer valueof(int i){  //注意static关键字
if(i>=-128 && i<=IntegerCache.high)
return IntegerCache.cache[i+128];
else
return new Integer(i);
}

静态工厂方法的优缺点:
优点:

  • 可以为静态工厂选择合适的命名,提高程序的可读性。
  • 静态工厂和简单工厂一样,可以封装复杂的初始化过程。
  • 避免了简单工厂类泛滥

缺点:

  • 一般为了强迫使用工厂方法,我们会让类只含有私有构造方法,这样,会导致此类不能被子类化。
  • 如果添加了一个新的该类的子类,此静态工厂方法可能需要重写,以加入该子类的实例化过程,导致扩展性不强。
  • 静态方法没有面向对象的特征,比如继承、动态多态等,不能被重写。

实例三、真正的模式之一:工厂方法模式

所有的工厂模式都用来封装对象的创建。工厂方法模式(Facotry Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

    /**
* 工厂方法模式.
* 工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。
* 工厂方法将类的实例化推迟到子类,
*
*/

public abstract class PizzaStore {
public Pizza orderPizza(){
Pizza pizza;

pizza=createPizza(); //不变的部分调用变化的部分

pizza.prepare();
pizza.cut();
pizza.box();
return pizza;
}

protected abstract Pizza createPizza();//变化的部分,工厂方法,由子类实现
}
//-------------------------------------------------------------------------
/**
* 实现了工厂方法。
*/

public class NewYorkPizzaStore extends PizzaStore{
@Override
protected Pizza createPizza() { //工厂方法的实现,创建类的对象。
return new NewYorkPizza();
}
}

实例四、真正的模式之二:抽象工厂模式

定义

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类

/**
* 抽象工厂,使用组合创建了一些列产品的集合。
*/

public interface PizzaIngredientFacotry { //接口中,每一种原料都有一个方法创建该原料。
public Sauce createSauce();
public Cheese createChesse();
}
//----------------------------------------------------------
/**
* 抽象工厂PizzaIngredientFactory的一种实现
* @see PizzaIngredientFacotry
*/

public class NYPizzaIngredientFacotry {
public Sauce createSauce(){ //返回具体的酱汁
return new NYSauce();
}
public Cheese createChesse(){
return new NYChesse();
}
}

实际上,抽象工厂的每个方法实际上看起来都像是工厂方法。每个方法都被声明成抽象的,而子类的方法覆盖这些方法来创建某些对象。没错,工厂方法潜伏在抽象工厂里面。抽象工厂的方法经常以工厂方法的方式实现。
抽象工厂的任务是创建一组产品的接口。这个接口内的每个方法都负责创建一个具体产品。所以,在抽象工厂中利用工厂方法实现生产方法是相当自然的做法。

与工厂方法的区别

  • 两者都是负责创建对象,但工厂方法使用的是继承,而抽象工厂使用的是对象的组合。
  • 工厂方法适合创建一类对象,即这类对象有共同的抽象。而抽象工厂适合把一组相关的产品集合起来,因为它用的是组合。
  • 对工厂方法来说,抽象创建者中所实现的代码通常会用到子类所创建的具体类型。
  • 当我们需要创建产品家族和想让制造的相关产品集合起来时,就可以使用抽象工厂。
  • 工厂方法的使用方式很简单,只要继承父类,在子类中实现其抽象方法即可。

效果

工厂模式让我们把对象实例化的过程进行了封装,屏蔽了复杂的构建过程。同时,工厂模式让客户类和具体类型解耦,增强了程序的可扩展性和可维护性。只有在需要考虑扩展性的时候才使用工厂方法模式,否则会增加代码的复杂程度。