设计模式学习(三) -- 工厂模式 Factory Pattern

简单工厂类:处理创建对象(封装对象的创建)的类,通常声明为静态的。

简单工厂不能算是一个设计模式,比较像是一种编程习惯,用来封装对象的创建。使用静态方法好处是不需要使用创建对象的方法来实例化对象,缺点是不能通过继承来改变创建对象方法的行为。

简单工厂类图
简单工厂

类图中,SimplePizzaFactory负责创建Pizza对象,PizzaStore是简单工厂类的客户,他们创建具体产品(CheesePizza, VegglePizza等)的行为都交给了简单工厂类来完成。

工厂方法:用来处理对象的创建,并将这样的行为封装到子类中。这样客户程序中关于超类的代码就喝子类对象创建代码解构了。

abstract Product factoryMethod(String type)

  • 工厂方法是抽象abstract的,所以依赖子类来处理实际的对象创建。
  • 工厂方法必须返回一个产品Product,超类中定义的方法通常使用到工厂方法的返回值。
  • 工厂方法factoryMethod将客户(超类中的代码)和实际创建具体产品(具体对象)的代码分隔开来。
  • 工厂方法可能需要参数(String type),也可能不需要参数,来指定所要的产品。

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

工厂方法模式类图
工厂方法模式

工厂方法模式中,抽象的Creator提供了一个创建对象的方法的接口factoryMethod(),称为”工厂方法“。Creator的其他方法(如anOperation()方法)都可能用工厂方法返回的产品Product,但只有Creator的子类(ConcreteCreator等)真正实现了工厂方法并创建具体的产品(ConcreteProduct)。所有的产品必须实现Product接口,这样使用产品的类Creator就可以引用这个接口而不是具体的产品类。

注意:所谓”决定“,并不是指模式允许子类本身在运行时做决定,而是指在编写创建者类Creator的时候,不需要知道实际创建的产品是哪一个。选择了使用哪个子类(如ConcreteCreator)自然就决定了实际创建的产品(ConcreteProduct)是什么。

设计原则:要依赖抽象,不要依赖具体类。
不能让高层组件依赖低层组件,而且两者都应该依赖于抽象。该原则也成为依赖倒置原则。

高层组件是有其他低层组件定义其行为的类。当你实例化一个对象时,就是在依赖对象的具体类。例如下图中,PizzaStore就是一个高层组件,它的行为由NYCheesePizza等低层组件定义。

高层组件依赖低层组件例子
高层组件依赖低层组件

如果低层组件NYCheesePizza的实现改变了,那么可能必须修改PizzaStore,因为PizzaStore依赖于NYChessePizza的实现。示例代码如下:

/**
 *
 * @author Yves
 */
public class PizzaStore {
    Pizza pizza;

    public Pizza orderPizza(String type){
        pizza = new NYCheesePizza();    //PizzaStore依赖了NYCheesePizza类
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}

应用工厂方法后,实例化对象的代码就被封装起来了,使得高层组件PizzaStore不再依赖于低层组件,而依赖于Pizza这个抽象。见下图:

应用工厂方法后实现依赖倒置DI
工厂方法实现了依赖倒置

具体的类NYCheesePizza等依赖Pizza这个抽象,因为它们实现Pizza接口。现在依赖关系就从高层PizzaStore依赖于低层NYCheesePizza 倒置 为NYCheesePizza依赖于Pizza。

public abstract class PizzaStore {
    Pizza pizza;

    public Pizza orderPizza(String type){
        pizza = this.createPizza(type);    //创建对象的任务交给工厂方法
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

    abstract Pizza createPizza(String type);    //工厂方法
}

避免违反依赖倒置原则的方法:

  • 变量不可以持有具体类的引用。(如果使用new就会持有具体类的引用,可以使用工厂方法来避免)
  • 不要让类派生自具体类。(要派生自一个抽象:接口或抽象类)
  • 不要覆盖积累中已经实现的方法。(基类中已经实现的方法应该由所有子类共享)

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

客户可以使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么。

抽象工厂通常用工厂方法来实现。抽象工厂提供的接口中,每个工厂方法负责创建一种具体产品,并且是利用实现抽象工厂的子类来提供具体的实现。

抽象工厂模式类图
抽象工厂模式类图

所有的具体工厂ConcreteFactory都必须实现抽象工厂定义的接口AbstractFactory,这个接口中的每个工厂方法,如CreateProductA,都负责创建一种具体的产品,如ProductA,具体创建的现实由具体工厂ConcreteFactory来提供。

/**
 *
 * @author Yves
 */
public interface AbstractFactory {
    public AbstractProductA createProductA();
    public AbstractProductB createProductB();
}
public class ConcreteFactory1 implements AbstractFactory{

    private AbstractProductA productA;
    private AbstractProductB productB;

    @Override
    public AbstractProductA createProductA() {
        productA = new ProductA1();
        return productA;
    }

    @Override
    public AbstractProductB createProductB() {
        productB = new ProductB1();
        return productB;
    }
}
public class ConcreteFactory2 implements AbstractFactory{

    private AbstractProductA productA;
    private AbstractProductB productB;

    public ConcreteFactory2(){

    }

    @Override
    public AbstractProductA createProductA() {
        productA = new ProductA2();
        return productA;
    }

    @Override
    public AbstractProductB createProductB() {
        productB = new ProductB2();
        return productB;
    }  
}
public interface AbstractProductA {

}
public interface AbstractProductB {

}
public class ProductA1 implements AbstractProductA{
    public ProductA1(){
        System.out.println("Create a ProductA1");
    }
}
public class ProductA2 implements AbstractProductA{
    public ProductA2(){
        System.out.println("Create a ProductA2");
    }
}
public class ProductB1 implements AbstractProductB{
    public ProductB1(){
        System.out.println("Create a ProductB1");
    }
}
public class ProductB2 implements AbstractProductB{
    public ProductB2(){
        System.out.println("Create a ProductB2");
    }
}
public class Client {
    private AbstractFactory factory;
    private AbstractProductA productA;
    private AbstractProductB productB;
    public AbstractProductA createProductA(){
        factory = new ConcreteFactory1();   //要创建一个产品,客户只需要使用其中一个具体工厂,而不需要实例化任何产品对象。
        productA = factory.createProductA();

        return productA;
    }

    public AbstractProductB createProductB(){
        factory = new ConcreteFactory2();   //要创建一个产品,客户只需要使用其中一个具体工厂,而不需要实例化任何产品对象。
        productB = factory.createProductB();

        return productB;
    }
}
public class FactoryTest {
     public static void main(String[] args){
        Client client = new Client();
        client.createProductA();
        client.createProductB();
    }
}
run:
Create a ProductA1  //选择了ConcreteFactory1这个工厂,所以生产出ProductA1    
Create a ProductB2  //选择了ConcreteFactory2这个工厂,所以生产出ProductB2    

抽象工厂模式使用组合而不是继承(工厂方法模式使用继承把对象的创建委托给子类,子类实现工厂方法来创建对象),客户Client只跟接口AbstractProductA,AbstractProductB,和AbstratcFactory产生关系,在创建具体产品的时候,选择合适的具体工厂ConcreteFactory就可以生产出相应的产品,而不需要在客户Client里面实例化具体产品类,从而把Client与具体产品解耦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值