「写在前面」
前言
简单工厂模式 属于创建型模式,不属于GoF设计模式,但是是学习其他 工厂模式 的基础。
创建型模式关注对象的创建过程,对类的实例化过程进行了抽象,使对象的创建和对象的使用分离,用户使用时,无须关心具体的创建细节。
简单工厂模式
一. 概述
通过工厂类中提供的方法,传入正确的参数,获取所需要的对象,通常被创建的实例对象有着同一个父类。
简单工厂模式 中将不同的产品对象的公共部分进行抽象、提取封装到一个公共的父类中,每个产品均是这个抽象类的子类,当需要使用这部分功能时,通过工厂类中的方法获取指定的实例对象。
所有工厂模式都强调:两个类A、B之间只能存在一种关系,由A创建B,或由A使用B,不能两个关系同时存在。
二. 结构
简单工厂模式包含三个部分: 工厂类 , 抽象产品类 , 具体产品类
工厂类
负责创建所有具体产品对象的内部逻辑,并提供可以被外部访问的方法,返回已经具体实例化的抽象产品对象。
抽象产品类
所有产品公共代码抽象后的产物,封装了所有产品的公有方法,所有产品类均需要实现或继承抽象产品类,实现类中的抽象方法。
具体产品类
调用者需要获取到的目标,实现或继承了抽象产品类,并实现了父类的抽象方法。
三. 实现
- 抽象产品类
// 抽象产品类
public abstract class Product {
// 所有产品类的公共业务方法
public void methodShared (){
// 业务方法
}
// 所有产品类的不同方法
public abstract void methodDifferent();
}
2. 具体产品类
// 具体产品类A
public class ProductA extends Product {
// A的业务方法
public void methodDifferent() {
// 具体实现逻辑
}
}
// 具体产品类B
public class ProductB extends Product {
// B的业务方法
public void methodDifferent() {
// 具体实现逻辑
}
}
3. 工厂类
// 工厂类
public class Factory {
public static Product getPro(String arg) {
Product product;
if ("A".equalsIgnoreCase(arg)) {
product = new ProductA();
// 初始化ProductA
} else if ("B".equalsIgnoreCase(arg)) {
product = new ProductB();
// 初始化ProductB
} else {
throw new Runtime Exception ("未知类型!");
}
return product;
}
}
4. 调用者
// 调用者
public class Invoker {
public void method(String arg) {
// 通过工厂类获取指定的产品对象
Product product = Factory.getPro("A");
// 执行具体业务
product.methodShared();
product.methodDifferent();
}
}
四. 案例
通过应用简单工厂模式设计一个可以创建不同集合形状的绘图工具,例如可以绘制如下图形:圆形(Circle),矩形(Rectangle)和三角形(Triangle)等等,且每个几何图形均具有绘制(draw())和擦除(erase())的方法。
- 通过案例描述可分析得出:
- 几何类作为抽象产品类
- 具体产品类为:圆形,矩形,三角形
- 共有方法为 擦除方法,每个几何图形的绘制方法不同需要定义为抽象方法由每个几何图形类实现。
2. 案例类图
3. 代码实现
- 几何类
public abstract class Geometry {
// 擦除功能
public void erase(){
System.out.println("擦除图形!");
}
// 绘制功能
public abstract void draw();
}
- 圆形、矩形、三角形
// 圆形类
public class Circle extends Geometry {
// 绘制圆形方法
@Override
public void draw() {
System.out.println("绘制圆形!");
}
}
// 矩形类
public class Rectangle extends Geometry {
// 绘制矩形方法
@Override
public void draw() {
System.out.println("绘制矩形!");
}
}
// 三角形类
public class Triangle extends Geometry {
// 绘制三角形方法
@Override
public void draw() {
System.out.println("绘制三角形!");
}
}
- 工厂类
// 工厂类
public class Factory {
// 获取几何图形方法。
public static Geometry getGeometry(String arg) {
Geometry geometry;
switch (arg) {
case "C":
geometry = new Circle();
System.out.println("初始化圆形类!");
break;
case "R":
geometry = new Rectangle();
System.out.println("初始化矩形类!");
break;
case "T":
geometry = new Triangle();
System.out.println("初始化三角形类!");
break;
default:
throw new RuntimeException("未知图形!");
}
return geometry;
}
}
- 测试类
public class ApiTest {
@Test
public void testGetGeometry(){
// 绘制圆形 并 擦除。
Geometry geometry = Factory.getGeometry("C");
geometry.draw();
geometry.erase();
}
}
执行结果 :
初始化圆形类!
绘制圆形!
删除图形!
如果更换图形修改调用方中的参数即可,例如需要绘制三角形则可以进行如下修改:
public class ApiTest {
@Test
public void testGetGeometry(){
Geometry geometry = Factory.getGeometry("T");
geometry.draw();
geometry.erase();
}
}
但是当前修改违背了 开闭原则 ,在变更时不得不重新编辑,可以将调用方的参数存储在配置文件中(可以是XML, YUM 等),通过读取配置文件的方式,进而改变调用者的入参。
变更为如下 :
public class ApiTest {
@Test
public void testGetGeometry(){
// 读取配置文件。
String age = XMLUtil.getAge();
Geometry geometry = Factory.getGeometry(age);
geometry.draw();
geometry.erase();
}
}
通过配置文件的引入,在不变更代码的情况下,实现参数的变更,符合 开闭原则 。
总结
优点
- 简单工厂模式中通过工厂类将对象的使用和对象的创建进行了分离,解除了使用和创建的耦合。
- 在一定程度上提高了系统的灵活性,通过配置文件可以在不修改任何代码的情况变更逻辑。
缺点
- 增加了系统中类的个数,进而使得徐彤的复杂度增加。
- 当需要增加新的产品时,必须修改原工厂方法,不利于系统的扩展和维护。
适用环境
- 工厂类负责创建的类相对较少,且具体产品不会随意变更。