本文主要介绍简单工厂模式(Simple Factory Pattern),它又叫静态工厂模式(Static Factory MethodPattern),它的定义是:“定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类”。
1. 模式介绍
工厂模式(Factory Design Pattern)是一种极为常用的用于创建对象的设计模式,在绝大部份开源框架中都有最佳实践,最为人所知的大概就是 Spring 的 BeanFactory 了。
工厂模式属于创建型模式,事实上它有三种不同的实现方式:简单工厂模式、工厂方法模式、抽象工厂模式。
本文主要介绍简单工厂模式(Simple Factory Pattern),它又叫静态工厂模式(Static Factory MethodPattern),它的定义是:“定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类”。
简单工厂模式并不属于 Gof23 种设计模式,只能算工厂模式的一种实现方法,因为它违背了设计模式六大原则的开放-封闭原则,因为每次添加一个产品类都需要在获取实例的方法中修改代码。
开放-封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。
2. 应用场景
简单工厂模式,顾名思义适用于比较简单的场景:
- 首先是需要创建的对象比较少,一只手掰的过来的那种
- 其次是客户端不关心对象的创建过程,这是工厂模式的普遍应用场景
3. 类图
简单工厂模式中有三种角色:
- 抽象产品(IProduct):描述了工厂创建的所有对象的抽象接口
- 具体产品(Concrete Product):工厂创建的具体实例,实现了抽象产品接口
- 简单工厂(Simple Factory):简单工厂模式的核心类,负责实现创建具体产品的逻辑。工厂类的创建具体产品的方法可以被外界直接调用。该方法一般是静态方法,所以简单工厂模式也被称为静态工厂模式。
这三种角色的类图如下所示:
4. 实现方式
下面就以一个具体的场景来展示简单工厂模式的实现方式。假设有一个用户现在想要用手机拍照,那么首先系统需要帮用户创建一个合适的手机,然后调用手机的通用能力——拍照来进行照相。
此时如果使用简单工厂来实现该需求,首先我们先来定义简单工厂模式种的抽象产品——手机的通用接口,也就是负责描述简单工厂创建的所有实例的公共接口:
public interface Phone {
void takePhotos();
}
随后定义两个具体产品类,实现Phone公共接口:
public class IPhone implements Phone {
@Override
public void takePhotos() {
System.out.println("IPhone...魔鬼前置");
}
}
public class HuaWei implements Phone {
@Override
public void takePhotos() {
System.out.println("华为...也能照亮你的美");
}
}
最后,创建简单工厂模式种最核心的简单工厂类,它有一个静态方法,可根据不同的如餐获得不同的具体产品类:
public class PhoneFactory {
/**
* 根据传入的手机品牌获得手机实体类
* 简单工厂:根据传入不同的参数创建不同的对象
* @param brand 手机品牌
* @return Phone
*/
public static Phone getPhone(String brand) {
Phone phone = null;
if (brand.equalsIgnoreCase("huawei")) {
phone = new HuaWei();
} else if (brand.equalsIgnoreCase("iphone")) {
phone = new IPhone();
}
return phone;
}
public static void main(String[] args) throws Exception {
Phone phone = getPhone("huawei");
phone.takePhotos();
}
}
// 输出
// 华为...也能照亮你的美
这样,我们就通过一个示例来实现了简单工厂模式。
5. 优缺点
简单工厂模式的优点:
- 有良好的封装性,将客户端域创建具体产品的逻辑解耦。客户端如果需要创建一个具体产品,只要知道这个具体产品的别名(类名或指定字符串)就可以了,不需要知道创建的具体流程
简单工厂模式的缺点:
- 拓展性较差,一旦有新的具体产品,需要修改简单工厂类创建具体产品方法的源代码才能生效,违反“开放-封闭原则”
- 简单工厂模式中创建具体产品方法通常使用静态方法实现,这会让子类无法继承,有一定限制
6. 优化简单工厂模式
简单工厂模式有一个缺点是拓展性较差,违反“开放-封闭原则”。这里有一种优化此缺点的方案——使用反射机制优化创建具体对象方法,使得简单工厂不违反开闭原则,具体代码如下:
public class NewPhoneFactory {
/**
* 使用反射解决简单工厂每次增加新手机(产品类)都需要改代码的弊端,使得简单工厂不违反开闭原则
*
* @param clazz
* @return Object
*/
public static Object getPhoneClass(Class<? extends Phone> clazz) {
try {
return Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
System.out.println("创建具体产品类失败,具体原因为:");
e.printStackTrace();
return null;
}
}
public static void main(String[] args) throws Exception {
// 传入的参数需要import或者类的全路径,可以使用配置文件的方式替代
IPhone iPhone = (IPhone) getPhoneClass(IPhone.class);
iPhone.takePhotos();
}
}
// 输出
// IPhone...魔鬼前置
7. 小结
本文描述了简单工厂模式的定义、应用场景、实现方式、优缺点以及一种简单工厂模式的优化方案。
8. 参考资料
- 设计模式之禅(第2版)
- 简单工厂模式_百度百科
最后,本文收录于个人语雀知识库: 我所理解的后端技术,欢迎来访。
文档信息
- 本文作者:Planeswalker23
- 本文链接:https://planeswalker23.github.io/2022/01/08/%E6%88%91%E6%89%80%E7%90%86%E8%A7%A3%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%B3%BB%E5%88%97-%E7%AC%AC2.1%E7%AF%87-%E4%B8%89%E7%A7%8D%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F%E5%82%BB%E5%82%BB%E5%88%86%E4%B8%8D%E6%B8%85%E6%A5%9A(1)%E7%AE%80%E5%8D%95%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/
- 版权声明:本作品系原创,作者保留所有权利,未经作者允许,禁止转载和演绎。