基本概念
工厂顾名思义就是创建产品。
该模式用于封装和管理对象的创建,是一种创建型模式。
工厂模式一般分为3类:
① 简单工厂模式(Simple Factory)
② 工厂方法模式(Factory Method)
③ 抽象工厂模式(Abstract Factory)
这三个模式从前到后,依次逐步抽象化。
简单工厂模式
概述
这是工厂模式中最简单的一种,专门定义一个类来负责创建其他类的实例,同时被创建的实例具有共同的父类。
简单工厂模式包括3个主要的角色:
简单工厂类(SimpleFactory):只包含创建产品的静态方法。
抽象产品父类(Product):简单工厂类中生产的产品接口,声明了产品的抽象方法。
具体产品子类(ProductA 或ProductB):具体产品的实现。
UML图
场景描述
某城市气候宜人,盛产水果,尤其盛产苹果(Apple)和香蕉(Banana),很多年来,各家果农都是自己负责苹果或香蕉的采摘、包装、销售,每个果农都要自备生产包装的设备,大家不能复用这些设备产出水果,因此生产效率非常低下。
有一个老总看到这个情况,决定投资建立了一家水果工厂(SimpleFactory),统一负责生产这些苹果或香蕉(Product),各家果农只要负责提供自己的苹果(ProductA)或者香蕉(ProductB),工厂负责根据果农的指定生产具体的水果(采摘、包装、销售等),因此生产流程效率大大提高,这就是简单工厂模式。
场景角色映射:
简单工厂类:SimpleFactory→FruitFactory。
类 FruitFactory 对应 SimpleFactory,它用来统一生产苹果或香蕉(包装、销售等),工厂中有一个静态方法CreateFruit(),就相当于一套流水线设备,可以根据提供的水果类型来生产不同的水果(Apple 或者 Banana)。
抽象产品父类:Product→Fruit。
水果接口类,统一定义苹果类和香蕉类的处理方法。
具体产品子类(ProductA或ProductB):ProductA→Apple,ProductB→Banana。
代码演示
抽象产品父类
代码语言:javascript复制package com.design; // 抽象产品父类
abstract class Fruit { // 构造方法
public Fruit(){ System.out.println("生产原料准备中。。"); }; // 定义水果的处理方法
public abstract void operateFruit(); }
ProductA(Apple)
代码语言:javascript复制package com.design; // 产品A
public class Apple extends Fruit{ @Override public void operateFruit() { // 苹果的生产过程
System.out.println("开始生产"); System.out.println("苹果:生产中。。。"); System.out.println("苹果:加工中。。。"); System.out.println("苹果:包装中。。。"); System.out.println("生产结束"); System.out.println("这是一个苹果"); } }
ProductB(Banana)
代码语言:javascript复制package com.design; // 产品B
public class Banana extends Fruit{ @Override public void operateFruit() { // 香蕉的生产过程
System.out.println("开始生产"); System.out.println("香蕉:生产中。。。"); System.out.println("香蕉:加工中。。。"); System.out.println("香蕉:包装中。。。"); System.out.println("生产结束"); System.out.println("这是一个香蕉"); } }
简单工厂类
代码语言:javascript复制package com.design; // 简单工厂类
public class FruitFactory { // 水果生产设备
public static Fruit createFruit(String type) { Fruit fruit = null; if ("A".equals(type)) { fruit = new Apple(); }else if ("B".equals(type)) { fruit = new Banana(); } return fruit; } }
测试:
代码语言:javascript复制package com.design; public class TestFactory { public static void main(String[] args) { // 创建工厂
FruitFactory factory = new FruitFactory(); // 1.生产苹果
Fruit apple = factory.createFruit("A"); apple.operateFruit(); System.out.println("------------------------------------"); // 2.生产香蕉
Fruit banana = factory.createFruit("A"); banana.operateFruit(); } }
运行结果:
简单工厂模式会专门创建一个工厂类FruitFactory,并用一个方法createFruit()根据传递参数的不同创建不同类型的实例。
这里要注意一点,在FruitFactory 中创建对象的类型可以不同(可以是苹果或者香蕉),但都应当属于同一个父类(抽象产品父类Fruit)的子类。
类FruitFactory 就是一个简单的工厂,将创建对象(苹果或香蕉)的工作单独负责下来,使得外界调用统一的方法 createFruit()即可完成不同对象创建(生产苹果或香蕉)。
工厂方法模式
概述
工厂方法模式是对简单工厂模式的改进,它去掉了简单工厂模式中工厂方法(例如,createFruit()这个方法)的静态属性,使得该方法能够被子类继承,将简单工厂模式中在静态工厂方法中集中创建对象的操作转移到各子类中完成,从而减轻了父类方法的负担。
工厂方法模式包括4个主要的角色:
抽象工厂类(AbstractFactory):工厂方法模式的核心,是具体工厂类必须实现的接口或者必须继承的抽象父类。
具体工厂类(ConcreteFactoryA 或者 ConcreteFactoryB):由具体的类来实现,用于创建工厂类的对象,它必须实现抽象工厂的方法。
抽象产品类(Product):具体产品继承的抽象父类或者实现的接口,定义了产品类的方法。
具体产品类(ProductA 或ProductB):具体工厂类产生的对象就是具体产品类的对象。
UML图
场景描述
接上文,随着生产规模的不断扩大,一个工厂一套设备生产苹果和香蕉已经不能满足公司的业务需求,所以公司的销售给老总建议,如果把苹果和香蕉的生产线分开生产效率会更高。原因有两点:一是两条生产线互不干扰进度,二是将来可方便增补其他水果的生产线从而扩展业务。
于是老总将原来的水果工厂进一步抽象整合,成立了一个水果公司集团(AbstractFactory),集团管理两家工厂,一家苹果厂(ConcreteFactoryA),一家香蕉厂(ConcreteFactoryB),集团只制定统一的规章制度,由这两家厂具体生产产品,一家生产苹果,一家生产香蕉,这就是工厂方法模式。
场景角色映射
抽象工厂:AbstractFactory→FruitCompany。
FruitCompany 类是实例中描述的水果公司类,该类相当于工厂方法模式中的抽象工厂AbstractFactory,它只用来制定规章制度(生产水果的方法),实际的生产都交给下面的具体工厂去做。
具体工厂:ConcreteFactoryA→AppleFactory,ConcreteFactoryB→BananaFactory。
AppleFactory 类和 BananaFactory 类分别表示苹果工厂类和香蕉工厂类,它们都要继承自抽象工厂类FruitCompany,苹果工厂按照水果公司的要求生产苹果;香蕉工厂按照水果公司的要求生产香蕉。
抽象产品:Product→Fruit。
水果接口类,统一定义苹果和香蕉的处理方法。
具体产品:ProductA→Apple,ProductB→Banana。
代码演示
抽象产品父类
代码语言:javascript复制package com.design; // 抽象产品父类
abstract class Fruit { // 构造方法
public Fruit(){ System.out.println("生产原料准备中。。"); }; // 定义水果的处理方法
public abstract void operateFruit(); }
ProductA(Apple)
代码语言:javascript复制package com.design; // 产品A
public class Apple extends Fruit{ @Override public void operateFruit() { // 苹果的生产过程
System.out.println("开始生产"); System.out.println("苹果:生产中。。。"); System.out.println("苹果:加工中。。。"); System.out.println("苹果:包装中。。。"); System.out.println("生产结束"); System.out.println("这是一个苹果"); } }
ProductB(Banana)
代码语言:javascript复制package com.design; // 产品B
public class Banana extends Fruit{ @Override public void operateFruit() { // 香蕉的生产过程
System.out.println("开始生产"); System.out.println("香蕉:生产中。。。"); System.out.println("香蕉:加工中。。。"); System.out.println("香蕉:包装中。。。"); System.out.println("生产结束"); System.out.println("这是一个香蕉"); } }
抽象工厂类
代码语言:javascript复制package com.design; // 抽象工厂类
abstract class FruitCompany { // 声明一个统一的水果生产方法
public abstract Fruit createFruit(); }
具体工厂A(AppleFactory)
代码语言:javascript复制package com.design; // 苹果工厂
public class AppleFactory extends FruitCompany{ @Override public Fruit createFruit() { Fruit fruit = new Apple(); return fruit; } }
具体工厂B(BananaFactory)
代码语言:javascript复制package com.design; // 香蕉工厂
public class BananaFactory extends FruitCompany{ @Override public Fruit createFruit() { Fruit fruit = new Banana(); return fruit; } }
测试:
代码语言:javascript复制package com.design; public class TestFactory { public static void main(String[] args) { // 创建工厂
FruitCompany factoryA = new AppleFactory(); FruitCompany factoryB = new BananaFactory(); // 1.生产苹果
Fruit apple = factoryA.createFruit(); apple.operateFruit(); System.out.println("------------------------------------"); // 2.生产香蕉
Fruit banana = factoryB.createFruit(); banana.operateFruit(); } }
运行结果:
工厂方法模式对简单工厂模式进行了改进,不是用一个工厂类来生产对象,而是用不同的具体工厂子类 AppleFactory 或 BananaFactory来生产不同的对象。
抽象工厂模式
概述
抽象工厂模式又是工厂方法模式的升级版本。它的主要思想:提供了一个创建一系列相关或者相互依赖对象的接口。
它和工厂方法模式的区别:抽象工厂模式针对的是有多个产品(称为产品族)的创建模式(苹果厂生产苹果、苹果脯;香蕉厂生产香蕉、香蕉干);而工厂方法针对的只是一种产品的创建模式(苹果厂生产苹果;香蕉厂生产香蕉)。抽象工厂模式中的抽象工厂接口里有多个工厂方法。
抽象工厂模式包括以下主要角色:
抽象工厂类(AbstractFactory):模式的核心,是具体工厂类必须实现的接口或者必须继承的抽象父类。
具体工厂类(ConcreteFactoryA 或者 ConcreteFactoryB):由具体的类来实现,用于创建工厂类的对象,它必须实现抽象工厂的方法。
抽象产品(AbstractProductA和AbstractProductB):具体产品继承的父类或者实现的接口,在Java中由抽象类或者接口实现。
具体产品(ProductA*或ProductB*):具体工厂类产生的对象就是具体产品类的对象。每一个抽象产品都可以有多个具体产品实现类或者继承子类,称为产品族。
UML图
场景描述
接上文,水果公司集团的经营良好,发展规模越来越大,集团全方位发展,产品也开始不再单一,而是向多个产品线(产品族)发展。原来的苹果厂不再单一地生产苹果,它开始生产苹果脯等深加工产品。香蕉厂也同样生产香蕉干等产品,这就形成了所谓的抽象工厂模式。
场景角色映射
抽象工厂类:AbstractFactory→FruitGroup。
成立一个水果集团(FruitGroup),该集团就相当于工厂方法模式中的抽象工厂,它的作用只用来制定规章制度(生产水果的方法),实际的生产都交给下面的具体工厂去做,下属多个工厂,有苹果厂、香蕉厂等。
具体工厂类:ConcreteFactoryA→AppleFactory;Concrete FactoryB→BananaFactory。
AppleFactory 类和 BananaFactory 类分别表示苹果工厂类和香蕉工厂类,它们都要实现抽象工厂FruitGroup,苹果工厂按照水果集团的要求生产苹果及苹果脯;香蕉工厂生产按照水果集团的要求生产香蕉和香蕉干。
抽象产品类:AbstractProductA→Fruit;AbstractProductB→DriedFruit。
Furit 类和 DriedFruit类分别为水果和水果脯类的抽象父类,具体产品类要继承这两个类。
具体产品:ProductA1→Apple,ProductA2→Banana;ProductB1→DriedApple,ProductB2→DriedBanana。
代码演示
抽象产品类(Fruit)
代码语言:javascript复制package com.design; // 抽象Fruit产品父类
abstract class Fruit { // 构造方法
public Fruit(){ System.out.println("生产原料准备中。。"); }; // 定义水果的处理方法
public abstract void operateFruit(); }
具体产品(Apple)
代码语言:javascript复制package com.design; // Fruit产品A
public class Apple extends Fruit{ @Override public void operateFruit() { // 苹果的生产过程
System.out.println("开始生产"); System.out.println("苹果:生产中。。。"); System.out.println("苹果:加工中。。。"); System.out.println("苹果:包装中。。。"); System.out.println("生产结束"); System.out.println("这是一个苹果"); } }
具体产品(Banana)
代码语言:javascript复制package com.design; // Fruit产品B
public class Banana extends Fruit{ @Override public void operateFruit() { // 香蕉的生产过程
System.out.println("开始生产"); System.out.println("香蕉:生产中。。。"); System.out.println("香蕉:加工中。。。"); System.out.println("香蕉:包装中。。。"); System.out.println("生产结束"); System.out.println("这是一个香蕉"); } }
抽象产品类(DriedFruit)
代码语言:javascript复制package com.design; // 抽象果脯产品父类
abstract class DriedFruit { // 果脯生产方法
public abstract void operateProduct(); }
具体产品(DriedApple)
代码语言:javascript复制package com.design; // 苹果干
public class DriedApple extends DriedFruit{ @Override public void operateProduct() { System.out.println("生产了一个苹果干"); } }
具体产品(DriedBanana)
代码语言:javascript复制package com.design; // 香蕉干
public class DriedBanana extends DriedFruit{ @Override public void operateProduct() { System.out.println("生产了一个香蕉干"); } }
抽象工厂类
代码语言:javascript复制package com.design; // 抽象工厂类,水果集团:生产水果和果脯。
abstract class FruitGroup { // 生产水果
public abstract Fruit createFruit(); // 生产果脯
public abstract DriedFruit createDriedFruit(); }
具体工厂类(AppleFactory)
代码语言:javascript复制package com.design; // 苹果工厂
public class AppleFactory extends FruitGroup{ @Override public Fruit createFruit() { Fruit fruit = new Apple(); return fruit; } @Override public DriedFruit createDriedFruit() { DriedFruit driedFruit = new DriedApple(); return driedFruit; } }
具体工厂类(BananaFactory)
代码语言:javascript复制package com.design; // 香蕉工厂
public class BananaFactory extends FruitGroup{ @Override public Fruit createFruit() { Fruit fruit = new Banana(); return fruit; } @Override public DriedFruit createDriedFruit() { DriedFruit driedFruit = new DriedBanana(); return driedFruit; } }
测试:
代码语言:javascript复制package com.design; public class TestFactory { public static void main(String[] args) { // 创建工厂
FruitGroup factoryA = new AppleFactory(); FruitGroup factoryB = new BananaFactory(); // 1.生产苹果
Fruit apple = factoryA.createFruit(); apple.operateFruit(); // 生产苹果干
DriedFruit driedApple = factoryA.createDriedFruit(); driedApple.operateProduct(); System.out.println("------------------------------------"); // 2.生产香蕉
Fruit banana = factoryB.createFruit(); banana.operateFruit(); // 生产香蕉干
DriedFruit driedBanana = factoryA.createDriedFruit(); driedBanana.operateProduct(); } }
运行结果:
抽象工厂是一个超级工厂,它生产了多种产品而不只是一种产品(例如,苹果工厂既可以生产苹果也可以生产苹果脯),因此它解决了工厂方法模式下一个工厂只能生产一种产品的局限问题。
抽象工厂模式隔离了具体类的生成,所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的代码,就能改变某个工厂的行为。
工厂模式总结
工厂模式,顾名思义就是生产对象的。
根据其抽象程度可分为以下三种:
简单工厂模式
一个工厂(具体工厂),生产多种产品,根据所传类型,生产相应的产品。
优点:
简单工厂类功能统一,使得外界从创建具体对象中分离出来,不用负责具体创建哪个类的对象,只要调用方法,由简单工厂统一创建即可。
缺点:
简单工厂类中集中了所有要创建的对象,如果需要添加新的创建对象类型,就必须改变简单工厂类的代码,这将违背开放封闭原则。这种情况在工厂方法模式中得到了部分解决。
工厂方法模式
一个公司(抽象工厂),生产多种产品,公司下面有多个工厂(具体工厂),每个工厂只生产一种产品。
优点:
解决了简单工厂模式中静态工厂方法在新增对象类型分支时需要修改方法代码的问题。在工厂方法模式中新增对象类型只需新增代码即可,不需要修改已有的代码,这样遵循了开放封闭原则,即对扩展开放,对修改封闭的原则。
缺点:
每增加一个产品类型,相应地也要增加一个子工厂,加大了额外的开发量。
抽象工厂模式
一个集团(抽象工厂),生产多个产品族的产品,集团下面有多个工厂(具体工厂),每个工厂只生产一个产品族的多种产品。
优点:
抽象工厂模式既具有工厂方法模式的上述优点,同时又解决了工厂方法模式一个具体工厂只能创建一类产品的局限,抽象工厂模式中每个工厂可以创建多种类型的产品(产品族)。同时,如果需要生产新的产品(不新增产品族),只需要扩展该产品对应的具体工厂和该产品的具体实现类,不需要改变抽象工厂类和抽象产品类。
缺点:
抽象工厂最大的缺点是产品族难以扩展。假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时对产品等级结构的划分是非常重要的。