设计模式之工厂方法模式

序言

简单工厂模式虽然简单,但是存在一个问题。 因为简单工厂模式是调用工厂类中的工厂方法,然后传入不同的参数来创建不同的产品,当引入一个新产品时,就需要修改工厂类,不符合“开闭原则”。 工厂模式不再提供一个工厂类来创建所有的产品对象,而是根据不同的产品来提供不同的工厂类。

工厂模式

定义 :定义一个用于创建对象的接口,让子类决定哪一个类实例化,创建具体的产品对象。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式,又可称作虚拟构造器模式或多态工厂模式。工厂模式是一种类创建型模式

工厂模式结构图

在工厂模式结构图有如下几个角色:

  • Product(抽象产品) : 定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。
  • ConcreteProduct(具体产品) : 它实现了抽象产品接口,某种类型的产品由专门的具体工厂创建,具体工厂和具体产品有一一对应关系。
  • Factory(抽象工厂): 在抽象工厂类中,声明了工厂方法用于返回一个产品,抽象工厂是工厂模式的核心,所有对象的工厂类都必须实现该接口。
  • ConcreteFactory(具体工厂): 它是抽象工厂的子类,实现了抽象工厂中的方法,并由客户端调用返回一个具体的产品。

与简单工厂模式相比,我们可以看到工厂模式多了一个抽象工厂角色。 抽象工厂可以是接口,也可以是抽象类或是类。

代码实现:

Product (抽象产品)

/**
 * @program
 * @Desc  抽象产品
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:38
 */
public interface Product {
}

ConcreteProduct(具体产品)

/**
 * @program
 * @Desc 具体产品A
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:39
 */
public class ConcreteProductA implements Product{
}

/**
 * @program
 * @Desc 具体产品B
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:40
 */
public class ConcreteProductB implements Product {
}

Factory(抽象工厂)

/**
 * @program
 * @Desc  抽象工厂
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:42
 */
public interface Factory {
    public Product factoryMrthod();
}

ConcreteFactory(具体工厂)

/**
 * @program
 * @Desc  具体工厂 A
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:46
 */
public class ConcreteFactoryA implements Factory {
    @Override
    public Product factoryMrthod() {
        return new ConcreteProductA();
    }
}
/**
 * @program
 * @Desc   具体工厂 B
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:48
 */
public class ConcreteFactoryB implements Factory {
    @Override
    public Product factoryMrthod() {
        return new ConcreteProductB();
    }
}

客户端测试

/**
 * @program
 * @Desc   客户端测试
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:51
 */
public class Test {
    public static void main(String [] args){
        //获取产品 A  只需获取 工厂 A
        Factory concreteFactoryA=new ConcreteFactoryA();
        Product productA= concreteFactoryA.factoryMrthod();
        //获取产品 B  只需获取 工厂 B
        Factory concreteFactoryB=new ConcreteFactoryB();
        Product productB= concreteFactoryB.factoryMrthod();
    }
}

我们可以看到客户端想要获取哪个具体厂品时,只需要跟据不同工厂来获取。 不像简单工厂模式中的一样,通过参数不同来获取。

重载的工厂方法

重载方法的工厂模式结构图

在UML类图可以看到,在工厂类中重载了工厂方法, 以不同的方法来创建。

代码实现:

Factory(抽象工厂)

/**
 * @program
 * @Desc  抽象工厂
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:42
 */
public interface Factory {
    public Product factoryMrthod();
    public Product factoryMrthod(String args);
    public Product factoryMrthod(int args);
}

ConcreteFactory (具体的工厂)

  /**
 * @program
 * @Desc  具体工厂 A
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:46
 */
public class ConcreteFactoryA implements Factory {
    @Override
    public Product factoryMrthod() {
       Product productA = new ConcreteProductA();
       //一般为默认方式创建产品
        return productA;
    }
    @Override
    public Product factoryMrthod(String args) {
        Product productA = new ConcreteProductA();
        // 有时创建产品时  产品对象需要String 型参数
        return productA;
    }
    @Override
    public Product factoryMrthod(int args) {
        Product productA = new ConcreteProductA();
        // 有时创建产品时 产品对象需要int 型参数
        return productA;
    }
}
//具体工厂 B ,也是如此   代码就不写了。

客户端测试:

 /**
 * @program
 * @Desc   客户端测试
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:51
 */
public class Test {
    public static void main(String [] args){
        //获取产品 A  只需获取 工厂 A
        Factory concreteFactoryA=new ConcreteFactoryA();
        Product productA1= concreteFactoryA.factoryMrthod("A");
        Product productA2= concreteFactoryA.factoryMrthod(0);
        Product productA3= concreteFactoryA.factoryMrthod();
    }
}

在抽象工厂方法中定义了几个重载的方法,在具体的工厂类中实现了这些工厂方法,这些方法可以包含不同的业务来满足不同产品对象的需求。

工厂方法的隐藏

有时候为了简化客户端的使用,我们可以隐藏工厂方法,直接在工厂类中调用产品类中的业务方法。客户端无需调用工厂方法来创建产品,然后调用产品业务方法。
隐藏工厂方法的工厂模式结构图

代码如下:

Product(抽象产品)

 /**
 * @program
 * @Desc  抽象产品
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:38
 */
public interface Product {
    public void productMethod();
} 

ConcreteProduct (具体产品)

  /**
 * @program
 * @Desc
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:39
 */
public class ConcreteProductA implements Product{
    @Override
    public void productMethod() {
        System.out.println("A 产品业务方法!!!");
    }
}

Factory(抽象工厂)

 /**
 * @program
 * @Desc  抽象工厂   改为抽象类
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:42
 */
public abstract class Factory {
    public abstract Product factoryMrthod();
    //产品业务方法
    public   void   productMethod(){
        Product product=this.factoryMrthod();
        product.productMethod();
    }
}

ConcreteFactory (具体工厂)

 /**
 * @program
 * @Desc  具体工厂 A
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:46
 */
public class ConcreteFactoryA extends Factory {
    Product productA;
    @Override
    public Product factoryMrthod() {
      
        return new ConcreteProductA();;
    }
}

客户端测试:

**
 * @program
 * @Desc   客户端测试
 * @Author 游戏人日常
 * @CreateTime 2019/07/14--13:51
 */
public class Test {
    public static void main(String [] args){
        ConcreteFactoryA factoryA= new ConcreteFactoryA();
        factoryA.productMethod(); //输出结果 : A 产品业务方法!!!
    }
}

把产品的业务方法移到工厂类中,可以直接使用工厂对象来调用产品的业务方法。无需使用工厂方法来获取产品,然后调用业务方法。

总结

工厂模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还解决了简单工厂模式中的一些不足。

上面出现两种工厂模式的变形: 1 : 重载工厂方法 2: 隐藏工厂方法

  • 重载工厂方法: 指的是重载工厂类中的工厂方法, 满足产品的业务需求。
  • 隐藏工厂方法 : 指得是把产品的业务方法移动到工厂类中, 只是想使用产品中的业务方法, 客户端不需创建产品对象。使用工厂对象来调用产品业务方法。

工厂模式优缺点:

优点
  • 客户端只需要关心所需产品的对应工厂,无需关心产品创建的细节。
  • 加入新的产品时,无需修改抽象产品和抽象工厂,也不需要修改具体的产品和具体工厂,只需要添加一个具体工厂和具体产品就行了,这样就符合”开闭原则“。
缺点
  • 添加新产品时,需要加入新的具体产品类和相对应的具体工厂类,导致系统中类的数量增加,在一定程度上增加了系统的复杂性。
  • 由于考虑系统的可扩展性,需引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度。
适用场景
  • 客户端不知道它所需要的对象的类,在工厂模式中,只需要知道所对应的工厂即可。
  • 抽象工厂类(Factory)通过其子类来指定创建哪个对象,在工厂模式中,抽象工厂类只需提供一个创建产品的接口,由它子类来确定具体所需的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象会覆盖父类的对象,从而使得系统容易扩展。
    一个游戏技术人,分享Java、Python、H5、Android 等知识。同时会分享游戏行业日常。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值