您现在的位置是:首页 >其他 >设计模式(二):创建型之工厂方法和抽象工厂模式网站首页其他
设计模式(二):创建型之工厂方法和抽象工厂模式
简介设计模式(二):创建型之工厂方法和抽象工厂模式
设计模式系列文章
目录
一、设计模式分类
- 创建型模式
- 用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”
- 提供了单例、原型、工厂方法、抽象工厂、建造者
5 种创建型模式
- 结构型模式
- 用于描述如何将类或对象按某种布局组成更大的结构
- 提供了代理、适配器、桥接、装饰、外观、享元、组合
7 种结构型模式
- 行为型模式
- 用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责
- 提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器
11 种行为型模式
二、概述
需求:设计一个咖啡店点餐系统
- 设计一个咖啡类(Coffee)
- 并定义其两个子类(美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】)
- 再设计一个咖啡店类(CoffeeStore),咖啡店具有点咖啡的功能
- 具体类的设计如下:
- 这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重
- 假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则
- 如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦
- 如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的
- 所以说,工厂模式最大的优点就是:
解耦
三、简单工厂模式
- 简单工厂不属于23种经典设计模式之一
- 简单工厂不是一种设计模式,反而比较像是一种编程习惯
1、结构
简单工厂包含如下角色:
- 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能
- 具体产品 :实现或者继承抽象产品的子类
- 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品
2、实现
现在使用简单工厂对上面案例进行改进,类图如下:
工厂类代码如下:
public class SimpleCoffeeFactory {
public Coffee createCoffee(String type) {
Coffee coffee = null;
if("americano".equals(type)) {
coffee = new AmericanoCoffee();
} else if("latte".equals(type)) {
coffee = new LatteCoffee();
}
return coffee;
}
}
- 如果需要Coffee对象直接从SimpleCoffeeFactory工厂中获取即可
- 这样也就解除了和Coffee实现类的耦合,同时又产生了新的耦合
- CoffeeStore对象和SimpleCoffeeFactory工厂对象的耦合
- 工厂对象和商品对象的耦合
- 如果再加新品种的咖啡,我们势必要需求修改SimpleCoffeeFactory的代码,违反了开闭原则
3、扩展:静态工厂
- 在开发中也有一部分人将工厂类中的创建对象的功能定义为静态的
- 这个就是静态工厂模式,它也不是23种设计模式中的
- 代码如下:
public class SimpleCoffeeFactory {
public static Coffee createCoffee(String type) {
Coffee coffee = null;
if("americano".equals(type)) {
coffee = new AmericanoCoffee();
} else if("latte".equals(type)) {
coffee = new LatteCoffee();
}
return coffe;
}
}
四、工厂方法模式
- 针对上例中的缺点,使用工厂方法模式就可以完美的解决,完全遵循开闭原则
- 定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象
- 工厂方法使一个产品类的实例化延迟到其
工厂的子类
1、结构
工厂方法模式的主要角色:
- 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应
2、 实现
使用工厂方法模式对上例进行改进,类图如下:
抽象工厂:
public interface CoffeeFactory {
Coffee createCoffee();
}
具体工厂:
public class LatteCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {
return new LatteCoffee();
}
}
public class AmericanCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {
return new AmericanCoffee();
}
}
咖啡店类:
public class CoffeeStore {
private CoffeeFactory factory;
public CoffeeStore(CoffeeFactory factory) {
this.factory = factory;
}
public Coffee orderCoffee(String type) {
Coffee coffee = factory.createCoffee();
coffee.addMilk();
coffee.addsugar();
return coffee;
}
}
- 要增加产品类时也要相应地增加工厂类,不需要修改工厂类的代码了,这样就解决了简单工厂模式的缺点
- 工厂方法模式是简单工厂模式的进一步抽象
- 由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点
3、优缺点
优点
- 用户只需要知道
具体工厂的名称
就可得到所要的产品,无须知道产品的具体创建过程 - 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则
缺点
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度
五、抽象工厂模式
-
工厂方法模式中考虑的是
一类产品
的生产,如畜牧场只养动物、电视机厂只生产电视机 -
工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产
多等级(种类)
的产品 -
本节要介绍的抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族
-
下图所示横轴是产品等级,也就是同一类产品
-
纵轴是产品族,也就是同一品牌的产品,同一品牌的产品产自同一个工厂
-
抽象工厂模式是工厂方法模式的升级版本
-
工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品
1、结构
抽象工厂模式的主要角色如下:
- 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品
- 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系
2、实现
- 现咖啡店业务发生改变,不仅要生产咖啡还要生产甜点,如提拉米苏、抹茶慕斯等
- 要是按照工厂方法模式,需要定义提拉米苏类、抹茶慕斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类,很容易发生类爆炸情况
- 拿铁咖啡和提拉米苏是同一产品族(也就是都属于意大利风味)
- 美式咖啡和抹茶慕斯是同一产品族(也就是都属于美式风味)
- 使用抽象工厂模式实现。类图如下:
抽象工厂:
public interface DessertFactory {
//生产咖啡的功能
Coffee createCoffee();
//生产甜品的功能
Dessert createDessert();
}
具体工厂:
//美式甜点工厂
public class AmericanDessertFactory implements DessertFactory {
public Coffee createCoffee() {
return new AmericanCoffee();
}
public Dessert createDessert() {
return new MatchaMousse();
}
}
//意大利风味甜点工厂
public class ItalyDessertFactory implements DessertFactory {
public Coffee createCoffee() {
return new LatteCoffee();
}
public Dessert createDessert() {
return new Tiramisu();
}
}
客户端:
- Coffee和Dessert是抽象产品类
- show(),抽象类中定义行为,具体实现交给子类
public class Client {
public static void main(String[] args) {
//创建的是意大利风味甜品工厂对象
//ItalyDessertFactory factory = new ItalyDessertFactory();
AmericanDessertFactory factory = new AmericanDessertFactory();
//获取拿铁咖啡和提拉米苏甜品
Coffee coffee = factory.createCoffee();
Dessert dessert = factory.createDessert();
System.out.println(coffee.getName());
dessert.show();
}
}
如果要加同一个产品族的话,只需要再加一个对应的工厂类即可,不需要修改其他的类
3、优缺点
优点
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的工厂对象
缺点
- 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改
六、JDK源码解析-Collection.iterator方法
public class Demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("令狐冲");
list.add("风清扬");
list.add("任我行");
//获取迭代器对象
Iterator<String> it = list.iterator();
//使用迭代器遍历
while(it.hasNext()) {
String ele = it.next();
System.out.println(ele);
}
}
}
- 对上面的代码大家应该很熟,使用迭代器遍历集合,获取集合中的元素
- 而单列集合获取迭代器的方法就使用到了工厂方法模式
- 通过类图看看结构
- Collection接口是抽象工厂类(声明Iterator iterator()方法)
- ArrayList是具体的工厂类(new Itr()创建返回Iterator对象)
- Iterator接口是抽象商品类(Itr实现Iterator接口类)
- ArrayList类中的Iter内部类是具体的商品(Itr是ArrayList内部类)
- 在具体的工厂类中iterator()方法创建具体的商品类的对象
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。