JAVA中的工厂模式也是一个重要的知识点,它除了在面试中问的比较多以外,这种模式的思想也是值得我们去学习的。
看了很多博客,大致的说法就是三类 简单工厂、工厂方法、抽象工厂,下面我们一一进行介绍,最后,我们再分析三种模式的区别。
一 、简单工厂模式
业务场景: 简单工厂模式主要运用在业务比较简单的情况下,适用于那种很少扩展的情况,工厂类几乎不变。
角色组成:
- 工厂类角色
- 抽象产品角色
- 具体产品角色
图示参考:
//抽象类,提取对象共有属性
abstract class Cup{
private String name;
private String price;
public abstract void drink();
}
//水杯
class WaterCup extends Cup{
public void drink() {
System.out.println("我喝水");
}
}
//咖啡杯
class CoffeeCup extends Cup{
public void drink() {
System.out.println("我喝咖啡");
}
}
//简单工厂
public class SimpleFactory {
public static Cup BuyCup(String str) {
Cup cup = null;
if(str.equals("买水杯")) {
cup = new WaterCup();
}else if(str.equals("买咖啡杯")) {
cup = new CoffeeCup();
}
return cup;
}
}
经过分析,客户端只负责消费产品,而不用自己去 “new"一个出来。从开闭原则方面来说,如果要增加一个新的产品,只需要再次继承抽象类即可,具有很好的扩展性(对扩展开放,对修改关闭)。但是在具体的工厂类中,需要判断多种业务,比较复杂。
二、工厂方法模式
角色组成:
- 抽象工厂角色
- 具体工厂角色
- 抽象产品角色
- 具体产品角色
下面 还是通过代码的方式来分析这几种角色,以及他相对简单工厂的优势。
//抽象工厂
abstract class Factory{
public abstract Cup buyCup();
}
//水杯工厂
class WaterCupFactory extends Factory{
public Cup buyCup() {
return new WaterCup();
}
}
//咖啡杯工厂
class CoffeeCupFactory extends Factory{
public Cup buyCup() {
return new CoffeeCup();
}
}
这里将工厂进一步抽象,实现工厂方法模式。上面在介绍简单工厂时说,在一个工厂类里面需要有复杂的逻辑,但是在将工厂抽象后,一个工厂只负责生产一种商品,用户不需要知道创建细节,将业务逻辑隔离开,符合高内聚低耦合的原则。而且如果要是增加一种产品的话,只需要增加抽象工厂和抽象产品的子类,不需要修改原有的逻辑代码,扩展性较简单工厂更好,符合开闭原则。
三、抽象工厂模式
 ; ;抽象工厂模式可以说是对工厂方法模式进一步抽象,在介绍抽象工厂方法模式之前,先介绍一下产品族的概念。产品族,指的是由同一个工厂生产的,位于不同产品等级结构中的一组产品。举个例子说明一下,大家都知道在汽车产业中有两种车,他们分别是普通商务车、和超级跑车,而生产汽车的企业又有很多种,比如奥迪、奔驰等,奥迪生产的普通商务车和奔驰生产的普通商务车是同属于一个“普通商务车”这样一个产品族中。类似的,奥迪和奔驰生产的超级跑车又属于“超级跑车”这个产品族中。
上一节我们在介绍简单工厂的时候,设计思路是一个工厂生产某一个具体的产品,但是如果产品过多的话,就得建造n多个工厂,而抽象工厂则是从产品族层面近一步抽象,设计为一个工厂生产一个产品族的产品。例如,商务车工厂生产奥迪、奔驰等等牌子的普通商务车,超级跑车工厂生产奥迪、奔驰、bmw等等牌子的超级跑车。这就是抽象工厂模式。
上面图中,一行也就是一个颜色等级的图案就代表一个产品族,由一个工厂生产,这样本来由15个工厂才能满足的逻辑,使用抽象方法后,只需要5个工厂就能满足,下面还是用代码的方式来说明(这回分为普通水杯子和饮料杯子)
//分析的时候 把玻璃杯和塑料杯当成两个不同的产品 然后根据他们的特征
// 都能装水 和饮料 所以 把水和饮料当成两个产品族 建造两个工厂 每个工厂都能生产玻璃杯和塑料杯
//抽象类,塑料杯子抽象
abstract class PlasticCup{
private String name;
private String price;
public abstract void drink();
}
//抽象类,玻璃杯子抽象
abstract class GlassCup{
private String name;
private String price;
public abstract void drink();
}
//玻璃水杯
class WaterGlassCup extends GlassCup{
public void drink() {
System.out.println("我用玻璃杯喝水");
}
}
//玻璃饮料杯
class DrinksGlassCup extends GlassCup{
public void drink() {
System.out.println("我用玻璃杯喝饮料");
}
}
//塑料水杯
class WaterPlasticCup extends PlasticCup{
public void drink() {
System.out.println("我塑料杯喝水");
}
}
//塑料饮料杯
class DrinksPlasticCup extends PlasticCup{
public void drink() {
System.out.println("我塑料杯喝饮料");
}
}
//分析 以上分别是 两个抽象类 分别是塑料杯 玻璃杯
// 根据他们的特征 都能装水和饮料 分为 水和饮料两个产品族
// 建造两个工厂
//抽象工厂 不管是玻璃杯还是塑料杯 都能生产水杯和饮料杯
abstract class CupFactory{
public abstract GlassCup createGlassCup();
public abstract PlasticCup createPlasticCup();
}
//实现水杯工厂
class WaterCupFactory extends CupFactory{
@Override
public GlassCup createGlassCup() {
return new WaterGlassCup();
}
@Override
public PlasticCup createPlasticCup() {
return new WaterPlasticCup();
}
}
//实现饮料杯工厂
class DrinkFactory extends CupFactory{
@Override
public GlassCup createGlassCup() {
return new DrinksGlassCup();
}
@Override
public PlasticCup createPlasticCup() {
return new DrinksPlasticCup();
}
}
class Factory{
public static void main(String[] args) {
//这里我想要买一个水杯,最好是玻璃的
CupFactory cupFactory = new WaterCupFactory(); //喝水建造水工厂
GlassCup cup = cupFactory.createGlassCup(); //玻璃水杯
}
}
如上代码所示,跟上面车的描述类似 ,装水和饮料是玻璃杯和塑料杯的特征,超级跑车和商务车也是奥利,奔驰等车的"特征",所以把特征区别不同族的产品,每一个产品族建造一个工厂,生产不同类型、牌子的产品,这就是抽象工厂模式。 但是抽象工厂也有缺点,如果,我们增加了一个新的产品树,也就是增加一个新的产品的牌子,除了要增加这个产品不同族的类之外,还要更改产品族工厂的代码,这样改动量太大,不太可取。所以下面我们将对抽象工厂进行改进,使用反射+简单工厂的方式来改进,但是这种方式的思想跟java设计模式中的策略模式很接近,所以放到下一节策略模式叙述。
四 、三种工厂模式的区别
简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品,增加产品需要修改工厂判断逻辑代码)
工厂方法 :用来生产同一等级结构中的固定产品。(支持拓展增加产品,增加产品不需要更改逻辑代码,子需要增加相应的工厂类,但容易造成工厂类冗余。)
抽象工厂 :用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族,可以改善工厂方法工厂类冗余的问题,但是增加产品的话,需要修改的代码较多,比如上面所讲增加一个汽车品牌的话,不仅要增加产品类,还要修改增加工厂方法)
五、注意事项
(1)工厂类常常采用单例模式(Singleton)。
(2)工厂类拥有基类(定义共同接口),基类可以为纯虚类,也可以定义缺省方法。
(3)对于工厂方法和抽象工厂,基类中的生产产品的函数常常为虚函数,以实现动态绑定。
(4)如果要把工厂方法当作参数作函数传递时,尽量使用其指针或引用,这样可以实例不同的工厂方法使用。