一、前言
- 学习概述:设计模式-----工厂方法模式
- 学习目标:掌握简单工厂模式、工厂方法模式、抽象工厂模式
二、概述
工厂模式的定义:定义一个用于创建产品对象的工厂,将对象的实际创建工作交给工厂来进行创建,满足创建型模式的“创建与使用相分离的特点”。
简单工厂模式不在23种设计模式之列,是一种简化的工厂方法模式。
工厂方法模式和抽象工厂模式属于五种创建型模式的两种(创建型模式有:单例模式、原型模式、工厂方法模式、抽象工厂模式、建造者模式)。
三、简单工厂模式
简单工厂模式不在23种设计模式之列。
简单工厂在创建实例时通常是静态方法创建,可以生产多种产品。
简单工厂在创建实例时没新增一种产品则需要新增一个工厂类和一个具体产品类,违背了“开闭原则”。
优点:
- 简单工厂包含必要的逻辑判断,知道在什么时候创建什么对象。
- 客户端无需知道类名,只需要知道参数即可
- 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类
缺点:
- 工厂类单一,负责所有产品的创建,职责过重。一旦异常对整个系统都有影响。
- 增加了系统中类的个数,造成系统臃肿。
- 系统扩展困难,每次新增产品都需要修改工厂类,违背了“开闭原则”。
- 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
1.UML图
2.例子
用简单工厂写一个简单加减计算器。
UML类图
运算接口:
定义一个运算接口
public interface Operation {
double getResult(double d1,double d2);
}
加法
加法类,实现加法运算
public class OperationAdd implements Operation {
@Override
public double getResult(double d1, double d2) {
return d1+d2;
}
}
减法
减法类,实现减法运算
public class OperationSub implements Operation {
@Override
public double getResult(double d1, double d2) {
return d1-d2;
}
}
工厂类
工厂类,按客户传递参数判断生生产出不同的运算类。
public class OperationFactory {
public static Operation createOperation(String symbol){
Operation operation = null;
switch (symbol){
case "+":
operation = new OperationAdd();
break;
case "-":
operation = new OperationSub();
break;
}
return operation;
}
}
运算结果
public static void main(String[] args) {
double d1 = 1.2;
double d2 = 2.1;
Operation operation = OperationFactory.createOperation("+");
double result = operation.getResult(d1, d2);
System.out.println("运算结果为:"+result);
}
运算结果为:3.3
3.总结
在使用简单工厂模式后,当要使用不同的运算,只需要在工厂生产对象的时候传递不同的参数便可以了,比如现在要进行减法运算,只需要在生产对象的时候 OperationFactory.createOperation(“-”)。此时所生产出来的对象便是OperationSub。进行的运算便是减法运算。
现在如果需要新增一种乘法运算,只需要新增一个乘法类实现Operation接口。同时在OperationFactory.createOperation中新增一个乘法判断即可。
public class OperationMul implements Operation {
@Override
public double getResult(double d1, double d2) {
return d1*d2;
}
}
public class OperationFactory {
public static Operation createOperation(String symbol){
Operation operation = null;
switch (symbol){
case "+":
operation = new OperationAdd();
break;
case "-":
operation = new OperationSub();
break;
case "*"://新增乘法
operation = new OperationMul();
break;
}
return operation;
}
}
开闭原则:当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求
前面说过简单工厂违背了开闭原则,就像这里,当再需要新增除法时,又需要去对工厂类中的代码进行修改。后面每当有新增都需要修改工厂类,因此违背了开闭原则。
四、工厂方法模式
工厂方法模式是对简单工厂模式的进一步抽象化,其好处是在不修改原有代码的情况下新增的功能,
满足了开闭原则。
在原有简单工厂模式基础上,根据依赖倒转原则,进一步抽象出一个接口,这个接口只有一个方法,就是创建抽象产品的工厂方法。在工厂方法模式上,每次新增新的产品只需新增一个新的工厂类和一个产品类即可,无需修改原有代码。
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
- 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
- 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
- 每次新增一种功能都需要新增一个工厂类和一个运算类,类的个数增多了,不便于维护。
- 增加的类的抽象程度和理解程度
- 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
1.UML图
2.例子
运算类
运算类同上述;
抽象工厂类
public interface IFactory {
Operation createOperation();
}
加法工厂类
实现抽象工厂类,创建加法运算类
public class AddFactory implements IFactory {
@Override
public Operation createOperation() {
return new OperationAdd();
}
}
减法工厂类
实现抽象工厂类,创建减法运算类
public class SubFactory implements IFactory {
@Override
public Operation createOperation() {
return new OperationSub();
}
}
运算结果
public static void main(String[] args) {
double d1 = 1.0;
double d2 = 2.0;
//创建加法工厂类
IFactory factory = new AddFactory();
//工厂类生产出运算类
Operation operation = factory.createOperation();
double result = operation.getResult(d1, d2);
System.out.println("运算结果为:"+result);
}
运算结果为:3.0
3.总结
如上述例子中,现在需要进行不同的运算时 ,不需要如同简单工厂模式一样传递不同的参数,只需要创建不同运算的工厂类便可以了。当需要新增一种乘法运算时,只需要新增一个乘法工厂类实现抽象工厂方法,在方法体里创建乘法运算即可。
public class MulFactory implements IFactory {
@Override
public Operation createOperation() {
return new OperationMul();
}
}