设计模式之工厂模式
工厂模式
一:简单工厂模式
1. 问题的引出
我们打算做一个制作pizza的系统,从订购到出货,初始代码如下:
public class pizza{ pizza orderpizza(string type){ pizza pizza; // 会引起代码变化的部分 if(type.equals("cheese")){ pizza =new cheesepizza(); }else if (type.equals("greek")){ pizza=new greekpizza(); }else if(type.equals("pepperoni")){ pizza=new pepperonipizza(); } //不需要改变的部分代码 这是对pizza的一系列处理 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
客户端通过调用pizza类的orderpizza方法来创建pizza,根据type的不同来获取不同种类的pizza,然而以上的设计存在着很多问题:
- pizza类中存在大量的if-else,使得整个类的代码冗长,既不容易测试又很影响性能 ,程序运行中需要做大量的条件判断。
- 当需要增加新的pizza的时候,必须修改pizza类的源代码,违反了开闭原则。
- 客户端只能通过new关键字来创建对象,使得pizza类和客户端耦合度很高,违反了迪米特法则。
因此我们引出了简单工厂模式
,此模式能在一定程度上解决这个问题
。
2. 简单工厂模式概述
简单工厂模式不属于gof23个经典设计模式,但它是学习工厂模式的基础,其思想:首先将需要创建的各种对象(各种风味pizza)封装到不同对象中,这些类称为具体产品类
,将公共部分提取到抽象产品类
,然后提供一个工厂类
用于创建各种产品,在工厂类中提供创建产品的工厂方法,根据参数获取不同的产品对象。
其定义如下:
简单工厂模式(simple factory pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(static factory method)模式,它属于类创建型模式。
3. 简单工厂模式结构图
4. 简单工厂模式角色
-
factory(工厂角色)
:即工厂类,负责创建所有产品实例的内部逻辑,其中提供了静态的工厂方法factorymethod(),外界直接调用此方法来返回抽象产品类型。 -
product(抽象产品角色)
:工厂类所创建的所有对象的基类,也是工厂类返回类型,符合依赖倒转原则以及开闭原则,封装了各种产品对象的公共方法。 -
producta(具体产品角色)
:由简单工厂创建得到,每个具体产品都继承或实现了抽象产品角色
在简单工厂模式中
5.简单工厂模式解决上述问题
抽象产品角色:
public interface ipizza { void prepare(); void bake(); void cut(); void box(); }
具体产品a:
public class pizzaa implements ipizza { @override public void prepare() { } @override public void bake() { } @override public void cut() { } @override public void box() { } }
具体产品b:
public class pizzab implements ipizza { @override public void prepare() { } @override public void bake() { } @override public void cut() { } @override public void box() { } }
工厂角色:
public class simplepizzafactory { public static ipizza createpizza(string type){ ipizza pizza=null; if(type.equals("a")){ pizza =new pizzaa(); }else if (type.equals("b")){ pizza=new pizzab(); } return pizza; } }
客户端:
public class client { public static void main(string[] args) { ipizza pizza = simplepizzafactory.createpizza("a"); // 创建pizza之后的工作 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } }
6:简单工厂模式总结
优点:
- 简单工厂模式使得对象的创建和使用分离开来。
- 简单工厂模式将创建对象的复杂逻辑封装起来。
- 使用者只需要传入参数即可获得对应的产品。
缺点:
- 违背开闭原则,一旦假如了新的产品就必须要更改工厂创建产品的逻辑。
- 工厂类集中所有产品的创建过程,一旦类不能正常工作,将引起整个系统的故障。
二:工厂方法模式
1.问题的引出
简单工厂模式虽然解决了产品对象的创建问题,但是仍然存在很大的设计问题:当添加新的产品时候,必须通过修改客户端传过去的类型参数,其次还需要修改工厂中的if-else逻辑,显然违反了开闭原则,此外简单工厂模式所有的产品都是同一个工厂所创,工厂类职责很重,违反了单一职责原则
,因此将引出第二种工厂模式->工厂方法模式。
2.工厂方法模式概述
不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构
,工厂方法模式定义如下:
工厂方法模式(factory method pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(factory pattern),又可称作虚拟构造器模式(virtual constructor pattern)或多态工厂模式(polymorphic factory pattern)。工厂方法模式是一种类创建型模式。
3.工厂方法模式结构图
4.工厂方法模式角色
-
product(抽象产品角色)
:用来定义产品的接口,是产品对象的基类。 -
productb(具体产品)
:实现了抽象产品接口 -
factory(抽象工厂)
:声明了工厂方法,用于返回一个产品,抽象工厂是工厂方法模式的核心,所有的工厂类都必须实现此方法。 -
productafactory(具体工厂)
:是抽象工厂子类,实现抽象工厂方法,返回具体的产品实例
5.工厂方法模式解决上述问题
结构如图:
代码如下:
抽象产品角色:
public interface pizza { // 准备 void prepare(); // 烘烤 void bake(); // 切 void cut(); // 装盒 void box(); }
具体产品角色:
public class pizzaa implements pizza { @override public void prepare() { system.out.println("pizzaa开始准备"); } @override public void bake() { system.out.println("pizzaa开始烘烤"); } @override public void cut() { system.out.println("pizzaa开始切"); } @override public void box() { system.out.println("pizzaa开始装盒"); } }
public class pizzab implements pizza { @override public void prepare() { system.out.println("pizzab开始准备"); } @override public void bake() { system.out.println("pizzab开始烘烤"); } @override public void cut() { system.out.println("pizzab开始切"); } @override public void box() { system.out.println("pizzab开始装盒"); } }
抽象工厂:
public interface pizzafactory { pizza createpizza(); }
具体工厂角色:
public class pizzaafactory implements pizzafactory { @override public pizza createpizza() { return new pizzaa(); } }
public class pizzabfactory implements pizzafactory { @override public pizza createpizza() { return new pizzab(); } }
客户端:
public class client { public static void main(string[] args) { // 针对抽象编程 pizzaafactory可根据di(依赖注入)进去 // 整个客户端就不需要对修改变化,全部是针对抽象编程 pizzafactory factory = new pizzaafactory(); pizza pizza = factory.createpizza(); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } }
6.工厂方法模式总结
优点:
- 对客户端隐藏了具体产品的创建细节,无需知道传入什么参数进去。
- 假如新产品时候,不需要更改客户端以及抽象产品角色以及抽象工厂角色,只需要添加新的工厂类以及具体产品即可,完全符合开闭原则。
缺点:
- 如果产品的个数种类很多,那么必然会出现大量的具体工厂类,增加了系统的复杂度,会给系统带来额外的开销。
三:抽象工厂模式
1.问题的引出
工厂方法通过引入工厂等级结构,解决简单工厂职责过重(所有的产品都在一个工厂里产生)的问题,但是工厂方法会额外产生大量的工厂类,producta、productb、productc........,会给系统带来很大的开销,因此我们可以将相同类型的产品组成产品族,由同一个工厂生产
,即抽象工厂模式的核心。
2.抽象工厂模式概述
抽象工厂模式为创建一组对象提供了解决方案,与工厂方法模式相比,抽象工厂模式中的工厂负责创建一组,其定义如下:
抽象工厂模式(abstract factory pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为kit模式,它是一种对象创建型模式。
3.抽象工厂结构图
- abstractfactory(抽象工厂):声明了一族产品的方法,每个方法对应一种产品。
- factory1(具体工厂):,实现了抽象工厂中的方法,生成一组具体产品,这些产品构成了产品族,某个产品都位于某个产品等级中。
- abstractproducta:不同产品实现或继承不同的产品接口。
- producta:具体产品,实现抽象产品中的方法。
4.抽象工厂模式实例
场景如下:为了保证客户的实用安全,确保原料一致,所以需要一个工厂来生产原料,即此工厂负责原料家族中的每种原料,即工厂需要生产面团、酱料、芝士等,但是不同区域的风味不一致,抽象工厂模式设计如下图:
代码如下:
abstractfactory(抽象工厂角色):
//原料生产工厂 每个区域的原料工厂都需要实现此接口 public abstract class pizzaingredientfactory { //每个原料都有一个对应的方法创建该原料 // 生产面团 abstract dough createdough(); // 生产酱 abstract sauce createsauce(); }
具体工厂:纽约原料加工厂
// 纽约原料工厂 public class nypizzaingredientfactory extends pizzaingredientfactory { @override dough createdough() { return new dougha(); } @override sauce createsauce() { return new saucea(); } }
具体工厂:中国原料加工厂
// 中国原料工厂 public class chinaingredientfactory extends pizzaingredientfactory { @override dough createdough() { return new doughb(); } @override sauce createsauce() { return new sauceb(); } }
抽象产品角色:面团
// 面团 public interface dough { }
抽象产品角色:酱料
// 酱料 public interface sauce { }
具体产品角色:面团a
public class dougha implements dough{ }
具体产品角色:面团b
public class doughb implements dough{ }
具体产品角色:酱料a
public class saucea implements sauce { }
具体产品角色:酱料b
public class sauceb implements sauce { }
5.抽象工厂方法总结
我们可以发现要是在增加新的产品族很方便,只需要扩展新的具体工厂,但是要扩展产品的等级结构(在抽象工厂中加入新的原料),会发现完全违背开闭原则,修改量巨大,抽象工厂的产品等级结构以工厂方法模式形式呈现,同样的产品族也是以工厂方法模式形式呈现,而产品族依赖产品等级结构,也就是说一旦产品等级结构是稳定不变的,那么整个抽象工厂就是很稳定的。
优点:
- 增加新的产品族很方便,完全符合对修改关闭
- 我们要替换整个产品线的话是非常容易的,只需要修改对应的具体工厂即可。
缺点:
- 增加新的产品等级结构需要修改大量的代码,完全违背开闭原则。
四:简单工厂vs工厂方法 && 工厂方法模式vs抽象工厂模式
先来回顾一下这三者的结构图:
简单工厂模式:
工厂方法模式:
抽象工厂模式:
简单工厂模式vs工厂方法模式
- 简单工厂模式把所有产品都放在一个工厂里生产。
- 简单工厂违背开闭原则。
- 工厂方法模式将产品的具体实现推迟到子类中,且针对每个产品都有对应的实现。
- 工厂方法模式符合开闭原则。
工厂方法模式vs抽象工厂模式
- 抽象工厂在产品族上符合开闭原则,但是在产品等级结构上违背开闭原则。
- 抽象工厂将一系类的产品组合起来,很明显符合组合复用原则。
- 抽象工厂可以看做是工厂方法的变形。相对于产品族来说,是工厂方法模式,相对于产品等级结构来说,也是工厂方法模式。