原创

浅谈工厂方法模式(Factory Method)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lishanleilixin/article/details/91899477

工厂方法模式

既然已经有了简单工厂模型了,为什么还有一个工厂方法模型呢?其实工厂方法模型就是为了解决简单工厂模型的缺点而产生的。简单工厂模型的缺点有哪些可以看这里:浅谈简单工厂方法模式,在此我们就不细说了。
总之,为了解决简单工厂模式的问题,我们又有了一种新的模式:工厂方法模式

工厂方法模式的介绍

工厂方法模型,又称为多态性工厂模型,在工厂方法模型中,核心的工厂类不再负责所有的产品的创建,而是将具体实例化的工作交给了子类完成。该核心工厂类成为一个抽象工厂角色,作用是给具体的工厂子类必须实现的接口,不接触具体实例化哪些产品的细节。

解决了哪些问题

  • 在简单工厂模型中,一旦添加新的产品类型就需要修改工厂类的逻辑。这违背了‘开放-闭合原则“
    • 而在工厂方法模型中,将具体的实例化操作放在了工厂子类中实现,工厂类成为一个抽象的类,不需要实现具体的细节操作,那么当有新的产品类型时,无需修改工厂类,只需要添加一个工厂子类就行了,这样符合“开闭原则”。

模式组成

在这里插入图片描述

角色 关系 作用
Product(抽象产品) 具体产品的父类 描述产品的公共接口
ConcreteProduct(具体产品) 抽象产品的子类;工厂类创建的目标类 描述具体生产的产品
Creator(抽象工厂) 具体工厂的父类 描述具体工厂的公共接口
ConcreteCreator(具体工厂) 具体工厂的父类 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例

表述代码

我们先实现抽象产品类

/**
 * 抽象产品类
 * @author lishanlei
 *
 */
public abstract class Product {

	//产品类的公共方法
	public void method1() {
		
	}
	
	public abstract void method2();
}

有了抽象产品类还不行,我们还需要具体的产品
ConcreteProduct1:

public class ConcreteProduct1 extends Product {

	public void method2() {
		//业务逻辑处理
		System.out.println("this is product 1...");
	}
}

ConcreteProduct2:

public class ConcreteProduct2 extends Product {

	public void method2() {
		//业务逻辑处理
		System.out.println("this is product 2...");
	}
}

现在我们定义一个抽象的工厂类,让它声明带实现的接口:

/**
 * 抽象工厂类
 * @author lishanlei
 *
 */
public abstract class Creator {

	public abstract <T extends Product> T createProduct(Class<T> c);
}

实现具体工厂类:

public class ConcreCreator extends Creator {

	@Override
	public <T extends Product> T createProduct(Class<T> c) {
		// TODO Auto-generated method stub
		Product product = null;
		try {
			product = (Product)Class.forName(c.getName()).newInstance();
		} catch (Exception e) {
			//异常处理
		}
		return (T)product;
	}
}

我们的客户端:

/**
 * 场景类
 * @author lishanlei
 *
 */
public class Client {

	public static void main(String[] args) {
		Creator creator = new ConcreCreator();
		Product product = creator.createProduct(ConcreteProduct2.class);
		product.method2();
		
		/**
		 * 继续业务处理
		 */
	}
}

运行结果:

this is product 2...

工厂方法模型的优点

  • 更加符合开闭原则
    • 新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可
  • 不使用静态工厂方法,可以形成基于继承的等级结构
    • 简单工厂模式的工厂类使用静态工厂方法
  • 具有良好的封闭性和可扩展性,代码的结构更加清晰

工厂方法模型的缺点

  • 增加新产品类型时,除了增加新产品类,还需要增加具体的工厂类,使得系统类的数目成对增加,一定程度上增加了系统的复杂度
  • 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类

工厂方法模型的使用场景

  • 在所有需要生成对象的地方都可以使用(需要慎重考虑是否值得使用)
  • 需要灵活的、可扩展的框架时
  • 可以使用在异构项目中
  • 在测试驱动开发的框架下使用

工厂方法模式的扩展

替代单例模式

单例模式的核心要求就是在内存中只有一个对象,通过工厂方法模式也可以只在内存中生产一个对象
在这里插入图片描述
Singleton定义一个private的无参数构造函数,目的是不允许通过new来创建一个对象

public class Singleton {
	
	private Singleton() {
		
	}
	
	public void doSomething() {
		//业务处理
		System.out.println("业务处理中...");
	}
}

Singleton保证了不能通过正常的渠道来创建一个对象,那么SingletonFactory如何建立一个单例对象呢?可以通过反射方式创建

import java.lang.reflect.Constructor;

public class SingletonFactory {

	private static Singleton singleton;
	
	static {
		try {
			Class c = Class.forName(Singleton.class.getName());
			Constructor constructor = c.getDeclaredConstructor();
			constructor.setAccessible(true);
			singleton = (Singleton)constructor.newInstance();
		} catch (Exception e) {
			//异常处理
		}
	}
	
	public static Singleton getSingleton() {
		return singleton;
	}
}

这样在项目中可以产生一个单例构造器,所有需要产生单例的类都遵循一定的规则,然后只要输入一个类型就可以获得唯一的一个实例。

延迟初始化

什么是延迟初始化?一个对象被消费完毕后,并不立即释放,工厂类保持其初始状态,等待再次被使用,延迟初始化是工厂方法模式的一个扩展应用。
在这里插入图片描述

//抽象产品类
public abstract class Product {

	public abstract void method();
	
}

ConcreteProduct:

public class ConcreteProduct1 extends Product {

	@Override
	public void method() {
		// TODO Auto-generated method stub
		System.out.println("product 1...");
		
	}
}

public class ConcreteProduct2 extends Product {

	@Override
	public void method() {
		// TODO Auto-generated method stub
		System.out.println("product 2...");
		
	}

}

工厂类:

public class ProductFactory {

	private static final Map<String, Product> prMap = new HashMap();
	public static synchronized Product createProduct(String type) throws Exception {
		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;
	}
	
}
文章最后发布于: 2019-06-13 21:50:42
展开阅读全文
0 个人打赏

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 终极编程指南 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览