概述
工厂模式的使用还是比较广泛的,它的作用也是显而易见的。主要作用是为对象的创建提供过度的接口,封装对象的具体创建过程和细节,达到高灵活性,对外只提供了工厂的接口,降低了模块之间的耦合性。
分类
工厂模式在习惯上分成了三类:
- 简单工厂模式:不属于23中设计模式
- 工厂方法模式:平常所说的工厂方法模式,一般指的是工厂方法模式
- 抽象工厂模式:将功能相关联的创建方法,封装到一个工厂中
在工厂模式的家族中,简单工厂模式是家族中的小弟,工厂方法模式是二哥,抽象工厂模式则是这个家族的大哥,它们的难度也是依次递增的,下面进行分类叙述。
简单工厂模式
简单工厂模式又称为静态工厂方法模式,该工厂的使用相对比较简单,应用也比较广泛,主要是根据客户端传入的参数,返回具体对象。
角色组成
- 抽象产品类角色:可以是一个接口或者抽象类是具体产品的父类,封装了产品的公有方法
- 具体产品类角色:继承或者实现了抽象产品类
- 简单工厂类角色:设计模式的核心类,对外提供一个静态方法,内部封装了各种产品的实现过程,客户端传入参数,工厂类根据参数,生成相应的具体产品对象,并返回。
示例
对于生活中,路口的信号灯而言,分为红灯、黄灯、绿灯、三种,现在就来模拟这种信号灯的展示。
//抽象产品类
public interface Light {
void display();
}
//具体产品类,红灯和黄灯
public class RedLight implements Light {
public RedLight(){
System.out.println("我是红灯,完成了创建");
}
@Override
public void display() {
System.out.println("红灯停,请注意安全!");
}
}
public class YellowLight implements Light {
public YellowLight(){
System.out.println("我是黄灯,完成了创建");
}
@Override
public void display() {
System.out.println("黄灯亮了,请等一等!");
}
}
//简单工厂类,关于客户端的调用没有另外创建类,直接放在了工厂类中
public class LightFactory {
public static Light getLight(String args){
Light light = null ;
if (args.equalsIgnoreCase("red")) {
light = new RedLight();
}
if (args.equalsIgnoreCase("yellow")) {
light = new YellowLight();
}
return light;
}
public static void main(String[] args) {
Light light = LightFactory.getLight("Red");
light.display();
System.out.println("-------------------");
light = LightFactory.getLight("yellow");
light.display();
}
}
关于简单工厂模式还有一种创建方法,就是将工厂类和抽象产品类进行合并,由抽象类来创建具体的产品对象也是可以的。
总结
优点
- 工厂类负责产品的创建,产品的创建过程对客户端不透明,客户端只负责使用产品类,这就就达到了创建使用分离的功能。
- 客户端无需知道具体产品的类名,只需要了解创建的参数就可以了,编程更高效,无序记忆复杂的类名
缺点
- 工厂类负责所有的产品的创建逻辑,使得工厂类的功能过重, 一旦不能正常工作,系统将瘫痪掉。
- 系统扩展困难,每次添加一个新的产品必须要修改工厂的代码
适用场景
工厂类负责创建的对象比较少,客户端只需要传入参数,对如何创建对象并不关心。
工厂方法模式
针对简单工厂模式的缺点,工厂模式又进行了升级,这便是工厂方法模式。在工厂方法模式中不再提供一个统一的类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,就是,创建一个抽象的工厂类来对外提供服务,而对象的创建过程交由实现了这个抽象工厂类的子类来完成,并且抽象工厂的子类和产品的子类形成一一对应的关系,一个具体产品类对应一个具体工厂类。
角色
- 抽象产品:定义产品的接口或者抽象类
- 具体产品类:实现或者继承了抽象产品的子类
- 抽象工厂类:声明了工厂方法
- 具体工厂类:实现了抽象工厂的方法,并可以由客户端调用,并返回具体的产品实例
接着上面的例子,来看一下工厂方法类的实现:
//抽象产品类
public interface Light {
void display();
}
//具体产品类
public class RedLight implements Light {
public RedLight(){
System.out.println("我是红灯,完成了创建");
}
@Override
public void display() {
System.out.println("红灯停,请注意安全!");
}
}
//抽象工厂类
public interface Factory {
Light getLight();
}
//具体产品类
public class RedLightFactory implements Factory {
@Override
public Light getLight() {
return new RedLight();
}
}
//客户端调用
public class Client {
public static void main(String[] args) {
Factory factory = new RedLightFactory();
Light light = factory.getLight();
light.display();
}
}
总结
优点
- 工厂方法来创建客户端所需要的产品,同时还想客户隐藏了具体产品的实例化细节,客户端只需要关心产品对应的工厂即可
- 在系统中加入新产品时,无需修改抽象工厂和抽象产品类
缺点
- 添加新的产品,就需要创建对应的一个工厂,造成了类的数量急剧的增加,需要加载和编译,增加了系统的开销
- 添加了抽象工厂,增加了理解难度
适用场景
- 客户端不需要知道它要创建的类,可以使用
- 抽象类通过子类来创建哪个工厂,可以使用
抽象工厂模式
工厂方法模式虽然解决了简单工厂模式职责过重的问题,但是新的问题又出现了,导致了系统中存在着大量的工厂类,增加了系统的开销。抽象工厂模式就是把一组之间有关系的产品放在了一个工厂中来产生。如果有15个产品类,使用工厂方法模式就会产生15个具体工厂,而抽象工厂模式生产的是产品族,一组产品族中包含3个具体的产品,需要5个具体工厂,具体工厂的数量就会大大减少。
角色
- 抽象产品:定义产品的接口或者抽象类
- 具体产品类:实现或者继承了抽象产品的子类
- 抽象工厂类:声明了工厂方法
- 具体工厂类:实现了抽象工厂的方法,并可以由客户端调用,并返回具体的产品实例
接上面的例子就行叙述,关于灯的分类可能有交通信号灯,日光灯,照明灯等,交通信号灯又分了红灯,绿灯等。
public interface Light {
void display();
}
public class RedLight implements Light {
public RedLight(){
System.out.println("我是红灯,完成了创建");
}
@Override
public void display() {
System.out.println("红灯停,请注意安全!");
}
}
public interface Factory {
Light getRedLight();
Light getYellowLight();
Light getGreenLight();
}
public class TrafficLightFactory implements Factory{
@Override
public Light getRedLight() {
return new RedLight();
}
@Override
public Light getYellowLight() {
return new YellowLight();
}
@Override
public Light getGreenLight() {
return null;
}
}
public class Client {
public static void main(String[] args) {
Factory factory = new TrafficLightFactory();
Light light;
light = factory.getRedLight();
light.display();
light = factory.getYellowLight();
light.display();
}
}
总结
优点
- 抽象工厂隔离了具体类的生成,对象的创建对客户端不透明
- 当一个对象产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
- 增加了新的产品族,并不需影响现有的代码
缺点
产品族的扩展非常的困难
适用场景
- 当系统中有多个产品族,而且一次只使用一个产品族时,可以使用
- 展品之间有相互的关系,例如创建一把枪,需要配备子弹,可以放在一个产品族中,可以使用。
上面的代码中为了好理解都是使用最普通的创建的方式,其实还有一个中常用的创建类的方式就是反射。
public abstract class Factory{
public abstract <T> T createProduct(Class<T> c ) ;
}
public class LightFactory extends Factory{
public <T> T createProduct(Class<T> c) throws Exception {
Product product = (Product) Class.forName(c.getName()).newInstanct() ;
}
}
少年听雨歌楼上,红烛昏罗帐。
壮年听雨客舟中,江阔云低,断雁叫西风。
感谢支持!
---起个名忒难
网友评论