本文介绍23种设计模式之工厂模式。
定义
- 工厂模式分为:简单工厂(严格来说不算设计模式),工厂方法,抽象工厂。属于创建型,用于将创建对象解耦。
- 工厂方法:定义一个创建对象的接口,有子类来实现体系的创建对象的操作。
- 抽象工厂:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
简单工厂
假如你经营一个餐厅,一开始只有一种炒饭,那么生成的方式很简单,直接创建即可。
public class MyRestaurant {
public FriedRice getFriedRice(){
FriedRice rice = new FriedRice();
rice.perpare(); //准备
rice.fry(); //炒
rice.loading();//装盘
return rice;
}
}
随着生意越来越好,要推新产品,就要加入多种炒饭,例如:鱼翅炒饭, 可以根据传入的类型去判断。
public class MyRestaurant {
public FriedRice getFriedRice(String type) {
FriedRice rice = null;
switch (type) {
case "sharkFin": //鱼翅炒饭
rice = new SharkFinFriedRice();
break;
case "beef"://牛肉炒饭
rice = new BeefFriedRice();
break;
case "yangzhou": //扬州炒饭
rice = new YangzhouFriedRice();
break;
}
rice.perpare(); //准备
rice.fry(); //炒
rice.loading();//装盘
return rice;
}
}
如果我需要根据市场情况将菜单进行添加和删除时就需要更改方法中的判断,违背了开闭原则,而且如果我开了第二家餐厅,需要复用就会出现重复代码。这时就想将不变的留下,变化的抽离出去,交给其他类处理。因此就将创建对象的方法抽离出去。
// 简单工厂
public class SimpleRiceFactory {
static FriedRice createFriedRice(String type){
FriedRice rice = null;
switch (type) {
case "sharkFin":
rice = new SharkFinFriedRice();
break;
case "beef":
rice = new BeefFriedRice();
break;
case "yangzhou":
rice = new YangzhouFriedRice();
break;
}
return rice;
}
}
public class MyRestaurant {
public FriedRice getFriedRice(String type) {
FriedRice rice = SimpleRiceFactory.createFriedRice(type); //交给简单工厂创建
rice.perpare();
rice.fry();
rice.loading();
return rice;
}
}
类图
总结来说,简单工厂就是将创建方法抽离出去,更像是一种编程习惯。
工厂方法
如果要开多家分店,每个店制作的虽然是同一种炒饭,但是口味偏好是有地区差异的。按照简单工厂的方式,可以通过不同的工厂进行创建,相当于有多少饭店就要创建多少工厂。那么我希望将创建和饭店进行绑定,又能够保证一定的弹性。比方说可以允许饭店自己创建炒饭,但是制作流程是固定的。就可以创建一个饭店的抽象类,让分店继承该类,由分店自己实现不同口味的。
//所有饭店的父类
public abstract class Restaurant {
//创建对象
public abstract FriedRice createFriedRice(String type);
// 统一制作流程
public FriedRice getFriedRice(String type) {
FriedRice rice = createFriedRice(type);
rice.perpare();
rice.fry();
rice.loading();
return rice;
}
}
public class MyRestaurant extends Restaurant{
@Override
public FriedRice createFriedRice(String type) {
FriedRice rice = null;
switch (type) {
case "sharkFin":
rice = new SharkFinFriedRice();
break;
case "beef":
rice = new BeefFriedRice();
break;
case "yangzhou":
rice = new YangzhouFriedRice();
break;
}
return rice;
}
}
描述
- 模式名称:FACTORY METHOD(工厂方法)
- 类型:类创建型模式
- 意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method使一个类的实例化延迟到其子类。
- 适用性:
- 当一个类希望由它的子类来指定它所创建的对象的时候。
- 当一个类不知道它所必须创建的对象的类的时候。
- 效果:
- 优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
- 可扩展性强,新增产品时只需要新增工厂类。
- 缺点:
- 类的个数容易过多,增加复杂度。
类图
案例类图
工厂方法模式定义了一个创建对象的接口,由子类决定要实例化的类是哪一个,工厂方法让类把实例化延迟到子类。
工厂方法类图
这里的interface泛指抽象类和接口
- 抽象工厂(Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 create() 来创建产品。
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
抽象工厂
刚才分析的饭店,我们知道每一道菜其实都是由这种材料组合而成的,不同的地方用料会有差异。原先的炒饭对象只是描述了行为,现在加上属性,也要对其进行封装,否则会导致关联的类太多,不利于维护,而且不符合依赖倒置原则。
因此需要先修改FriedRice类,添加相应属性和产品类
public abstract class FriedRice {
Rice rice;
Seasoning seasoning;
Meat meat;
abstract void perpare();
abstract void fry();
abstract void loading();
}
添加抽象工厂,用于创建FriedRice
//抽象工厂
public interface AbstractFriedRiceFactory {
public Rice createRice();
public Seasoning createSeasoning();
public Meat createMeat();
}
//实现类1
public class SpicyBeefFriedRiceFactory implements AbstractFriedRiceFactory {
@Override
public Rice createRice() {
return new NortheastRice();
}
@Override
public Seasoning createSeasoning() {
return new LaoGanMa();
}
@Override
public Meat createMeat() {
return new Beef();
}
}
//实现类2
public class JueweiBeefFriedRiceFactory implements AbstractFriedRiceFactory {
@Override
public Rice createRice() {
return new WuchangRice();
}
@Override
public Seasoning createSeasoning() {
return new JwSeasoning();
}
@Override
public Meat createMeat() {
return new Beef();
}
}
创建FriedRice实现类,传入想要实现的工厂对象
public class BeefFriedRice extends FriedRice {
AbstractFriedRiceFactory factory;
//通过抽象工厂类进行解耦
public JueweiBeefFriedRice(AbstractFriedRiceFactory factory) {
this.factory = factory;
}
@Override
void perpare() {
meat = factory.createMeat();
seasoning = factory.createSeasoning();
rice = factory.createRice();
}
}
最终修改下饭店代码
public class MyRestaurant extends Restaurant{
@Override
public FriedRice createFriedRice(String type) {
FriedRice rice = null;
// 通过修改传入的工厂类进行更改,也可以通过外部传入
// AbstractFriedRiceFactory factory = new JueweiBeefFriedRiceFactory();
AbstractFriedRiceFactory factory = new SpicyBeefFriedRiceFactory();
switch (type) {
case "beef":
rice = new BeefFriedRice(factory);
break;
}
return rice;
}
}
描述
- 模式名称:ABSTRACT FACTORY(抽象工厂)
- 类型:对象创建型模式
- 意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
- 适用性:
- 一个系统要由多个产品系列中的一个来配置时。
- 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
- 效果:
- 优点:
- 分离了具体的类,易于切换具体工厂。
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
- 缺点:
- 难以扩展抽象工厂以生产新种类的产品,新增产品就要修改抽象工厂的代码,就破坏了开闭原则。
类图
案例类图
抽象工厂模式提供接口,用于创建相关或依赖对象的家族,而不需要制定明确类。在上述场景中通过使用抽象工厂,让上层模块和底层模块解耦,上层模块因此不需要关系具体的类是什么。
抽象工厂类图
- 抽象工厂(AbstractFactory):提供了创建产品的接口,它包含多个创建产品的方法 createProduct(),可以创建多个不同的产品。
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
总而言之,无论哪种工厂模式,目的就是为了解耦,将创建对象的功能剥离出去,无论是通过继承交由子类实现(工厂方法),还是通过接口创建相应的对象族(抽象工厂)。