创建型(三)—工厂模式

1、介绍

工厂模式又叫虚拟构造函数模式或者多态性工厂模式。可分为简单工厂、工厂方法和抽象工厂模式。

  1. 简单工厂: 一个工厂类处于对产品类实例化的中心位置上,它知道每一个产品,决定哪一个产品应当实例化。优点是允许客户端相对产品创建的过程,并在系统引入新产品时无需修改客户端,但需要修改工厂类,在某种程度上支持开闭原则,但支持力度不够。
  2. 工厂方法:是简单工厂模式的进一步抽象和推广,在该模式中,核心工厂类不在负责所有产品的创建,而是将具体的创建工作交给子类去做。这个核心类则成为一个抽象工厂角色,只需给出具体工厂子类必须实现的接口,无需关注哪个产品类实例化的细节。这种可以允许系统在不修改具体工厂角色的情况下引进新产品。
  3. 抽象工厂:是所有形态的工厂模式中最为抽象和最具有一般性的形态。抽象工厂模式与工厂模式的最大区别在与,工厂方法模式针对的是一个产品等级结构;而抽象工厂则需要处理多个产品等级结构。

2、工厂模式

Define an interface for creating an object,but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

意思是: 定义一个用于创建对象的接口,在子类决定实例化那个类。工厂方法使一个类的实例化延迟到其子类。

使用场景:

  1. 工厂模式是new一个对象的替代品,因此在所有需要生产对象处都可以使用,但需慎重考虑是否增加一个工厂类进行管理,增加代码的复杂度。
  2. 需要灵活的,可扩展的框架

3、UML类图


角色介绍:

  1. Factory : 是工厂模式的核心,与应用系统无关,具有的工厂类必须实现这个接口。
  2. ConcreteFactory:实现接口,与应用层密切交互,收到应用程序的调用以及创建产品对象。
  3. Product:负责定义产品的共性,实现对产品最抽象的定义。
  4. ConcreteProduct:实现抽象产品角色所声明的接口,工厂模式所创建的每一个对象都是某个具有产品的实例。

抽象产品类

public abstract class Product {
	/**
	 * 产品类的抽象方法,由具体的产品类去实现
	 */
	public abstract void method();
}

具体产品类A

public class ConcreteProductA extends Product{

	@Override
	public void method() {
		System.out.println("我是具体产品A");	
	}
}

具体产品类B

public class ConcreteProductB extends Product{
	@Override
	public void method() {
		System.out.println("我是具体产品B");	
	}
}

抽象工厂类

public abstract class Factory {
	/**
	 * @return 具体的产品对象
	 */
	public abstract Product createProduct();
}

具体工厂类

public class ConcreteFactory extends Factory {

	@Override
	public Product createProduct() {
		return new ConcreteProductA();
	}
}

客户类

public class Client {

	public static void main(String[] args) {
		Factory factory = new ConcreteFactory();
		Product product = factory.createProduct();
		product.method();
	}
}

上述的代码运行结果得到的产品对象时ConcreteProductA的实例,若是想得到ConcreteProductB的实例,需更改ConcreteFactory中的代码:

public class ConcreteFactory extends Factory {
	@Override
	public Product createProduct() {
//		return new ConcreteProductA();
		return new ConcreteProductB();
	}
}

若是还有ConcreteProductC产品,创建该产品的实例,则又要修改代码,显然方式有缺陷。这里可以利用反射的方式来生产具体的产品对象。在抽象工厂类中传入一个Class类来决定是哪一个产品类:

public abstract class Factory {
	/**
	 * @param clz 产品对象类类型
	 * @return 具体的产品对象
	 */
	public abstract <T extends Product> T createProduct(Class<T> clz);
}

对于具体的工厂类,则可以通过反射创建类实例。

public class ConcreteFactory extends Factory {

	@Override
	public <T extends Product> T createProduct(Class<T> clz) {
		Product product = null;
		try {
			product = (Product) Class.forName(clz.getName()).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return (T) product;
	}
}

在Client中需要创建哪个产品实例,就传入哪个类的类型即可,这个方法简洁,动态。

public class Client {

	public static void main(String[] args) {
		Factory factory = new ConcreteFactory();
		Product pA = factory.createProduct(ConcreteProductA.class);
		pA.method();
		Product pB= factory.createProduct(ConcreteProductB.class);
		pB.method();
	}
}

4、示例

 以车厂生产汽车为例,比如:需要生产模块汽车,车型有Q1, Q2。首先构造抽象工厂类

public abstract class CarFactory {
	/**
	 * 某车型的工厂方法
	 * @param clz  具体的车型号
	 * @return  具体的车型号的车对象
	 */
	public abstract <T extends Car> T createCar(Class<T> clz);
}

所生产的两种车型在主结构上并没有什么差异,所以只需要一种生产线即可:

public class ConcreteCarFactory extends CarFactory {
	@Override
	public <T extends Car> T createCar(Class<T> clz) {
		Car car = null;
		try {
			car = (Car) Class.forName(clz.getName()).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return (T) car;
	}
}

对于两种车型,都有行驶和自动驾驶的功能,抽象出汽车的接口如下:

public abstract class Car {
	/**
	 * 定义车可以有启动行驶功能
	 */
	public abstract void drive();
	/**
	 * 定义车可以有自动导航功能
	 */
	public abstract void selfNavigation();
}

接下来就是生产Q1和Q2两种类型的车。

public class CarQ1 extends Car {

	@Override
	public void drive() {
		System.out.println("Q1启动了!");
	}

	@Override
	public void selfNavigation() {
		System.out.println("Q1开始自动导航了");
	}
}
public class CarQ2 extends Car {

	@Override
	public void drive() {
		System.out.println("Q2启动了!");
	}

	@Override
	public void selfNavigation() {
		System.out.println("Q2开始自动导航了");
	}

}

最后我们将各个类组装起来形成一条完整的流水线:

public class Client {
	public static void main(String[] args) {
		CarFactory factory = new ConcreteCarFactory();
		CarQ1 carQ1 = factory.createCar(CarQ1.class);
		carQ1.drive();
		carQ1.selfNavigation();
		
		CarQ2 carQ2 = factory.createCar(CarQ2.class);
		carQ2.drive();
		carQ2.selfNavigation();
	}
}

输出结果如下:

Q1启动了!
Q1开始自动导航了
Q2启动了!
Q2开始自动导航了

5、总结

优点:

  1. 良好的封装性,代码结构清晰。一个对象创建是有条件约束的,若一个调用者需要一个具体的产品对象,只要知道这个产品的类名或约束字符串即可,无需关注创建对象的过程,降低了模块之间的耦合度。
  2. 优秀的可扩展性,在增加产品类时,只要在调用是输入产品的类名或扩展一个具体的工厂类。
  3. 解耦框架,高层模块只需要知道产品的抽象类,其他的实现类都不用关心。工厂模式符合迪米特法则 和依赖倒置原则,只依赖产品类的抽象;另外还符合里氏替换原则,可以使用产品子类替换产品父类。

缺点:为工厂模式添加新的产品就得编写一个新的产品类。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值