设计模式-工厂模式,介绍工三种工厂模式,及代码实现。
简介
工厂模式属于创建型模式,提供了创建对象的最佳方式,定义了一个创建对象的接口,让其子类自己决定实例化哪个工厂类,工厂模式使其创建过程延迟到子类进行。
优势
- 解耦,创建对象和使用对象分开
- 降低代码的重复
- 降低维护成本
分类
工厂模式可以分成三类:
- 简单工厂模式,又称静态工厂模式
- 工厂方法模式,又称多态性工厂模式
- 抽象工厂模式,又称工具箱模式
本文代码参考大话设计模式,即用java实现工厂模式。需求:用java代码实现简单计算器功能,包括加减乘除等功能。
简单工厂
简单工厂模式适合简单的场景,因为如果新增功能进行维护时,需要修改原来代码,在switch/if 代码修改添加,这样的话就违反了设计模式的开闭原则。
角色
- 工厂角色:对外开放接口,调用者通过调用工厂的方法获得实例,工厂内部方法通过外部传入的参数实例化需要的具体实例
- 抽象类角色:具体实例的父类,负责描述所有实例的公共接口(计算接口)
- 具体类角色:简单工厂模式的创建目标,创建的对象为具体操作的实例(具体的计算操作类,加减乘除)
实现设计
- 创建计算器操作的操作抽象类
- 创建计算子类加减乘除类分别继承操作抽象类
- 创建工厂类,创建计算方法,可通过计算的标识,获得具体的操作类
- 客户端可通过调用工厂类,实现计算器功能
代码实现
操作抽象类
1 2 3 4 5 6 7 8 9 10 11
|
public abstract class Operation { public double numberA; public double numberB;
public abstract double result(); }
|
具体操作类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
public class OperationAdd extends Operation {
@Override public double result() { return numberA + numberB; }
}
public class OperationSub extends Operation {
@Override public double result() { return numberA - numberB; }
}
public class OperationMul extends Operation {
@Override public double result() { return numberA * numberB; }
}
public class OperationDiv extends Operation {
@Override public double result() { if (numberB == 0) { throw new RuntimeException("除数不可以为0!"); } return numberA / numberB; }
}
|
工厂类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
public class OperationFactory { public static Operation createOperation(char operator) { Operation operation = null;
switch (operator) { case '+': operation = new OperationAdd(); break; case '-': operation = new OperationSub(); break; case '*': operation = new OperationMul(); break; case '/': operation = new OperationDiv(); break; default: throw new RuntimeException("unsupported operation"); }
return operation; } }
|
客户端调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public class Calculator { public static void main(String[] args) { Operation operation; char operator;
operator = '*'; operation = OperationFactory.createOperation(operator); operation.numberA = 1; operation.numberB = 2;
System.out.println(operation.result()); } }
|
改善
可通过反射改善简单工厂模式的“违反开闭原则”,即在工厂类获得实例的方法中,通过类的方式来获得类,配合配置文件可灵活配置。
工厂方法
工厂方法模式是简单工厂的进一步深化,工厂方法模式不在提供统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。
角色
- 抽象工厂角色
- 具体工厂角色
- 抽象实例角色
- 具体实例角色
实现设计
- 创建抽象的工厂接口,定义统一的获取实例的方法
- 创建获取加减乘除实例的工厂,实现抽象工厂接口
- 创建抽象实例操作类,定义结果方法、操作数属性(同简单工厂)
- 创建具体实例类,继承抽象实例(真正的加减乘除,同简单工厂)
代码实现
抽象工厂接口
1 2 3 4 5 6 7 8 9
|
public interface IFactory {
Operation createOperation(); }
|
具体工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
public class AddFactory implements IFactory {
@Override public Operation createOperation() { return new OperationAdd(); }
}
class SubFactory implements IFactory {
@Override public Operation createOperation() { return new OperationSub(); }
}
class MulFactory implements IFactory {
@Override public Operation createOperation() { return new OperationMul(); }
}
class DivFactory implements IFactory {
@Override public Operation createOperation() { return new OperationDiv(); }
}
|
客户端调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
public class FactoryClient { public static void main(String[] args) {
IFactory divFactory = new DivFactory(); Operation div = divFactory.createOperation(); div.numberA = 3; div.numberB = 4;
System.out.println(div.result()); IFactory addFactory = new AddFactory(); Operation add = addFactory.createOperation(); add.numberA = 3; add.numberB = 4;
System.out.println(add.result()); IFactory mulFactory = new MulFactory(); Operation mul = mulFactory.createOperation(); mul.numberA = 3; mul.numberB = 4;
System.out.println(mul.result()); IFactory subFactory = new DivFactory(); Operation sub = subFactory.createOperation(); sub.numberA = 3; sub.numberB = 4;
System.out.println(sub.result());
} }
|
缺点
由于具体工厂都实现了相同的接口,即获得实例方法的返回实例是相同的。也就是说工厂方法获得实例都必须继承同一父类,通过工厂方法只能获得同一“品类”(相同父类)的实例。
抽象工厂
抽象工厂模式是对工厂方法模式的改进,用于处理实例不是同一类的情况,将实例都继承同一抽象类,改为实现接口。
角色
- 抽象工厂角色
- 具体工厂角色
- 抽象实例角色
- 具体实例角色
实现设计
- 创建抽象工厂接口,定义两个方法,分别是一个获取加法减法接口的方法、一个是获取乘法除法接口的方法
- 创建获取加法乘法实例的具体工厂,和获取减法除法实例的具体工厂
- 创建加法减法的抽象实例接口,和乘法除法的抽象实例接口
- 创建加法减法实例实现加法减法接口,创建乘法除法实例实现相应接口
代码实现
抽象工厂接口
1 2 3 4 5 6 7 8 9 10 11 12
|
public interface IAbsFactory {
IOperationAddSub createOperationAddSub();
IOperationMulDiv createOperationMulDiv(); }
|
具体工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
public class AddMulAbsFactory implements IAbsFactory {
@Override public IOperationAddSub createOperationAddSub() {
return new OperationAbsAdd(); }
@Override public IOperationMulDiv createOperationMulDiv() {
return new OperationAbsMul(); } }
public class SubDivAbsFactory implements IAbsFactory {
@Override public IOperationAddSub createOperationAddSub() {
return new OperationAbsSub(); }
@Override public IOperationMulDiv createOperationMulDiv() {
return new OperationAbsDiv(); } }
|
抽象实例接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
public interface IOperationAddSub {
double result(double numberA,double numberB); }
public interface IOperationMulDiv {
double result(double numberA,double numberB); }
|
具体实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
public class OperationAbsAdd implements IOperationAddSub{
@Override public double result(double numberA,double numberB) { return numberA + numberB; }
}
public class OperationAbsSub implements IOperationAddSub {
@Override public double result(double numberA,double numberB) {
return numberA - numberB; }
}
public class OperationAbsMul implements IOperationMulDiv {
@Override public double result(double numberA,double numberB) { return numberA * numberB; }
}
public class OperationAbsDiv implements IOperationMulDiv {
@Override public double result(double numberA,double numberB) { if (numberB == 0) { throw new RuntimeException("除数不可以为0!"); } return numberA / numberB; }
}
|
优缺点