JAVA设计模式之--工厂方法模式

JAVA设计模式之--工厂方法模式

Scroll Down
小提示,本文编写于  2,223  天前,最后编辑于  1,895  天前,某些信息可能有些出入,仅供参考。

在现实生活中社会分工越来越细,越来越专业化。

各种产品有专门的工厂生产,彻底告别了自给自足的小农经济时代,这大大缩短了产品的生产周期,提高了生产效率。同样,在软件开发中能否做到软件对象的生产和使用相分离呢?

能否在满足“开闭原则”的前提下,客户随意增删或改变对软件相关对象的使用呢?

工厂方法模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂方法模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

定义: 定义一个创建对象的接口,但让实现这个接口的类来决定要实例化那个类,工厂方法让类的实例化延迟到子类进行。

类型: 创建型

使用场景

创建对象需要大量重复的代码

客户端(应用层)不依赖与产品类实例如何被创建、实现细节

一个类通过其子类来指定创建那个对象

优点

用户只需要关心所需产品的对应工厂,无序关心创建细节

加入新的产品符合开闭原则,提高扩展性

缺点

类的个数容易过多,增加复杂度

增加了系统的抽象性和理解难度

分析

工厂方法中一个工厂只生产一种产品,这样可以保证了工厂的唯一性,这点是和抽象工厂最大的区别。例如:冰箱工厂只能生产冰箱不能生产其他产品。

我们可以通过提供一个或者一组重载方法来完成产品的定制。比如格力冰箱实现/继承冰箱方法抽象/接口类完成自己工厂的创建,美的冰箱同样也可以实现/继承冰箱抽象/接口类来完成自己工厂的创建。

由于他们都是实现了统一的冰箱接口和冰箱方法类,那么客户端(应用层)只需要使用冰箱接口接口来根据自己需求获取自己需要的产品,并不需要知道具体的创建过程和细节。这也是编程中面向接口编程的思想。

案例

进入夏天正是冰箱售卖的好时节,供应商小李想采购一批冰箱售卖。那么他就需要知道冰箱的品牌和价格,而且他有可能采购不同厂商的冰箱。冰箱工厂会定义好的商品来生成。

1. 定义产品即可和工厂接口**

/**
 * 冰箱接口
 */
public interface IRefrigerator {
    //获取品牌名
    String getBrandName();

    //获取价格
    double getPrice();
}
/**
 * 冰箱工厂接口
 */
public interface IRefrigeratorFactory {

    IRefrigerator getIRefrigerator();
}

2. 产品实现类**

/**
 * 海尔冰箱
 */
public class HaiErRefrigerator implements IRefrigerator {
    @Override
    public String getBrandName() {
        return "海尔冰箱";
    }

    @Override
    public double getPrice() {
        return 5999;
    }
}
/**
 * 美的冰箱
 */
public class MeiDiRefrigerator implements IRefrigerator {
    @Override
    public String getBrandName() {
        return "美的冰箱";
    }

    @Override
    public double getPrice() {
        return 2999;
    }
}
/**
 * 格力冰箱
 */
public class GeLiRefrigerator implements IRefrigerator {
    @Override
    public String getBrandName() {
        return "格力冰箱";
    }

    @Override
    public double getPrice() {
        return 3999;
    }
}

3. 工厂实现类

/**
 * 海尔冰箱工厂
 */
public class HaiErRefrigeratorFactory implements IRefrigeratorFactory {
    @Override
    public IRefrigerator getIRefrigerator() {
        return new HaiErRefrigerator();
    }
}
/**
 * 美的冰箱工厂
 */
public class MeiDiRefrigeratorFactory implements IRefrigeratorFactory {
    @Override
    public IRefrigerator getIRefrigerator() {
        return new MeiDiRefrigerator();
    }
}
/**
 * 格力冰箱工厂
 */
public class GeLiRefrigeratorFactory implements IRefrigeratorFactory {
    @Override
    public IRefrigerator getIRefrigerator() {
        return new GeLiRefrigerator();
    }
}

4. 测试类

/**
 * 测试类
 */
public class Test {

    public static void main(String[] args) {
        IRefrigeratorFactory refrigeratorFactory = new HaiErRefrigeratorFactory();
        IRefrigeratorFactory refrigeratorFactory2 = new GeLiRefrigeratorFactory();
        IRefrigeratorFactory refrigeratorFactory3 = new MeiDiRefrigeratorFactory();
        IRefrigerator refrigerator = refrigeratorFactory.getIRefrigerator();

        System.out.println("您购买了:" + refrigerator.getBrandName() + ",您需要支付:" + refrigerator.getPrice());
    }
}

5. 日志信息

您购买了:海尔冰箱,您需要支付:5999.0

回到开头讲到的,来复盘一次

优缺点和适用环境

工厂方法模式的优点

1)用户只需要关心产品对应的工厂,甚至无需关心创建细节或具体产品类的类名  
2)基于工厂角色和产品的多态性设计是工厂模式的关键。它能自主决定如何创建哪种产品对象,而创建细节都封装在具体工厂内部
3)在系统要添加新的产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,只要添加一个具体工厂和具体产品即可,从而提高系统的可扩展性(符合开闭原则) 

工厂方法模式的缺点

1)在添加新产品时,要编写新的具体产品类,并要提供与之对应的具体工厂类。系统软件个数也成对增加,从而增加了系统的复杂度,带来更多开销
2)由于系统的可扩展性,在客户端中要引入抽象层进行定义,从而增加了系统的抽象性和理解难度

工厂方法模式的适用环境

1)客户端不需要知道它需要的对象的类。只需知道对应的工厂即可
2)抽象工厂类通过子类来指定创建那哪个对象。即抽象工厂类只需要提供一个创建产品的接口,而由其子类确定具体要创建的对象,利用多态性和里氏代换原则,子类对象将覆盖父类对象,从而使系统更容易扩展