工厂模式定义
工厂模式的定义:Define an interface for creating an Object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.(定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。)
简单工厂
简单工厂模式:Simple Factory Pattern,又叫静态方法模式,即一个具体的工厂类,可以生成多个不同的产品。
应用场景:一般用于产品种类较少的情况,使用简单工厂模式可以方便的创建所需产品,只需要传入相关参数,而不用考虑实现细节
UML 图:
简单工厂主要有三个角色:
- 简单工厂:简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象
- 抽象产品(IProduct):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口
- 具体产品(ConcreteProduct):是简单工厂模式的创建目标
通用写法
// 抽象产品类
public abstract class Product {
// 产品类的公共方法
public void method1(){
// 业务处理逻辑
}
// 抽象方法
public abstract void method2();
}
// 具体产品类
public class ConcreteProduct1 extends Product {
@Override
public void method2() {
// 业务逻辑处理
}
}
public class ConcreteProduct2 extends Product {
@Override
public void method2() {
// 业务逻辑处理
}
}
// 抽象工厂类
public abstract class Creator {
/**
* 创建一个产品对象,其输入参数可以自行设置
* 通常是String、Enum、Class等,当然也可以为null
*/
public abstract <T extends Product> T createProduct(Class<T> c);
}
// 具体工厂类
public class ConcreteCreator extends Creator {
@Override
public <T extends Product> T createProduct(Class<T> c) {
Product product = null;
try {
product = (Product)Class.forName(c.getName())
.getConstructor().newInstance();
} catch (Exception e){
// 异常处理
}
return (T) product;
}
}
// 场景类
public class Client {
public static void main(String[] args) {
Creator creator = new ConcreteCreator();
Product product = creator.createProduct(ConcreteProduct1.class);
/*
* 继续业务处理
*/
}
}
枚举模式实现简单工厂
使用枚举类型实现简单工厂有两种方式:
// Product接口
public interface Product {
void say();
}
// 产品实现1
public class Pro1 implements Product{
@Override
public void say(){
System.out.println("产品1");
}
}
// 产品实现2
public class Pro2 implements Product{
@Override
public void say() {
System.out.println("Pro2");
}
}
1、枚举非静态方法实现工厂方法模式
public enum SimpleFactoryEnum {
PRO1,
PRO2;
public Product create() {
switch (this) {
case PRO1:
return new Pro1();
case PRO2:
return new Pro2();
default:
throw new UnsupportedOperationException("非法操作!");
}
}
}
2、使用抽象方法实现工厂,具体实现由枚举子类实现
public enum SimpleFactoryEnum1 {
PRO1() {
@Override
public Product create() {
return new Pro1();
}
},
PRO2() {
@Override
public Product create() {
return new Pro2();
}
};
// 抽象方法,由子类实现
public abstract Product create();
}
工厂模式优点和缺点
优点:
- 良好的封装性,代码结构清晰,即一个对象的创建是有条件约束的,调用者在需要一个具体的产品对象时只需知道对象的类名或约束字符串,而无需知道创建过程;
- 可扩展性好,只需要适当的修改具体的工厂类或扩展一个工厂类,就可以完成扩展;
- 屏蔽产品类,有利于后序可能的升级,因为无论产品类如何变化都不会影响上层模块;
- 用于解耦,实现框架
缺点:
- 简单工厂模式的工厂类,负责所有产品的创建,当产品基数增多时,工厂类代码会非常臃肿,违背高聚合原则
简单工厂的应用
- java 的 Calendar 类中的 Calendar.getInstance() 方法
- Logback 源码 Logger.getLogger() 方法
简单工厂
properties 文件作为配置文件,使用反射获取配置。
步骤:
创建接口和实现
public interface UserService {
void print();
}
public class UserServiceImpl implements UserService {
@Override
public void print() {
System.out.println("Hello");
}
}
applicationContext.properties配置
# UserService的类路径
userService=com.example.service.impl.UserServiceImpl
简单工厂
public class BeanFactory {
private static final Properties properties = new Properties();
static {
try(final InputStream resource = BeanFactory.class
.getResourceAsStream("/applicationContext.properties")){
// 通过磁盘IO加载properties文件
properties.load(resource);
} catch (IOException e) {
e.printStackTrace();
}
}
public static UserService getUserService(){
UserService userService = null;
try {
// 通过类路径获得UserService实现的Class对象
final Class<?> clazz =
Class.forName(properties.getProperty("userService"));
// 通过反射实例化对象
userService = (UserService)clazz.newInstance();
} catch (ClassNotFoundException |
IllegalAccessException |
InstantiationException e) {
e.printStackTrace();
}
return userService;
}
public static void main(String[] args) {
final UserService userService = getUserService();
userService.print();
}
}
测试
public static void main(String[] args) {
final UserService userService = BeanFactory.getUserService();
userService.print();
}
通用工厂:由于上述简单工厂每多一个类均需要一个工厂方法,因此可以对工厂类的工厂方法进行改造,通过传入一个 key 来获取相应的对象:
使用:
- 定义类型(类)
- 通过配置文件的配置告知工厂(applicationContext.xml):key=value
- 通过工厂获得类的对象:
Object ret = BeanFactory.getBean("key");
public static Object getBean(String key){
Object ret = null;
try {
// 通过类路径获得Class对象
final Class<?> clazz = Class.forName(properties.getProperty(key));
// 通过反射实例化Class对象
ret = clazz.newInstance();
} catch (ClassNotFoundException |
IllegalAccessException |
InstantiationException e) {
e.printStackTrace();
}
return ret;
}