工厂方法模式
工厂模式提供了一种创建对象的最佳方式,在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。前文介绍过工厂模式属于创建型模式
意图
定义一个创建对象的接口,让其子类自己决定实例滑哪个工厂类,工厂模式使其创建过程延迟到子类进行
通用类图
Product通常是接口,负责定义产品的共性,实现对事物最抽象的定义。ConcreteProduct是product的实现类,主要负责具体如何创建产品。Creator为抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂ConcreteCreator完成的。
通用代码实现
public abstract class Product {
// 产品类的公共方法
public void method1(){
// 业务处理逻辑
}
// 抽象方法
public abstract void method2();
}
public class ConcreteProduct2 extends Product{
@Override
public void method2() {
// 业务处理逻辑
}
}
public class ConcreteProduct1 extends Product{
@Override
public void method2() {
// 业务处理逻辑
}
}
public abstract class Creator {
/**
* 创建一个产品对象,其输入参数类型可以自行设置
* @param c
* @return
* @param <T> 产品类型
*/
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()).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
return (T) product;
}
}
工厂模式优点
良好的封装性,代码结构清晰一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道产品的类型就可以了,不用知道创建对象的艰辛过程,降低模块间的耦合。其次扩展性非常优秀,上述代码中我们可以看出,在新增产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成。可以看出工厂方法模式是典型的解耦框架,高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则。不需要的就不用管,也符合依赖倒置原则,只依赖产品类的抽象,也符合里氏替换原则。
工厂模式使用场景
日志记录器:记录日志可能记录到本地硬盘、系统事件、远程服务器等、用户可以选择记录日志到什么地步
数据库访问:当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时
设计一个连接服务器的框架,需要三个协议,”POP3″、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口;
工厂方法模式的扩展
可以缩小为简单工厂模式
当一个模块仅需要一个工厂类,没有必要把它生产出来的时候使用静态的方法就可以了。
升级为多个工厂类
当我们在做一个比较复杂的项目时,经常会遇到初始化一个对象很耗费精力的情况,所有的产品类都放到一个工厂方法中进行初始化会使代码结构不清晰。例如一个产品类有多个具体实现,每个实现类的初始化方法都不相同,如果写在一个工厂方法中,就会导致该方法巨大无比。考虑到需要代码结构清晰,我们可以为每个产品定义一个创建者,每个创建者都独立负责创建对应的产品对象,非常符合单一职责原则。
延迟初始化
何为延迟初始化(Lazy initialization)?一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。延迟初始化是工厂方法模式的一个扩展应用。
代码示例:
public class ProductFactory {
private static final Map<String, Product> prMap=new HashMap<>();
public static synchronized Product createProduct(String type){
Product product=null;
if (prMap.containsKey(type)){
product=prMap.get(type);
}else {
if (type.equals("Product1")){
product=new ConcreteProduct1();
}else {
product=new ConcreteProduct2();
}
prMap.put(type,product);
}
return product;
}
}
核心思想就是通过HashMap和synchronized 关键字 来保证同一时间只能有一个线程创建并且通过map去判断是否已经创建过了。
工厂方法模式思考
什么时候使用工厂模式以及什么时候使用多个工厂类都是一个我们值得思考的问题。有的时候我们可能使用工厂模式的话会导致类变得特别多,在一定程度上也会导致我们的代码难以维护。但是这个世界上就没有完美的事情嘛。是否使用以及如何使用就根据每个人对于代码的理解,以及系统后续的扩展性和发展来考量了。
欢迎大家在评论区留言,大家对于工厂方法模式个人独特的见解,以及在日常工作中有没有遇见过工厂模式的具体实现。