目录
工厂模式
博主一句话总结(非准确): 工厂模式就是将创建产品类交给工厂去处理,对于同一种产品的不同类型,可以通过抽象工厂来实现扩展性,如果有多种产品就可以再抽象一层工厂,让工厂可以生产更多的产品。这样当需要扩展时,只需要在提供方增加对应的类,使用方依旧只需要调用工厂的接口即可获取产品,符合ocp原则。
1. 简单工厂(不属于23种)
- 概念:简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例
- 实现:定义一个创建对象的类,由这个类来封装实例化对象的行为
- 应用场景:当我们会大量地创建某种、某类或者某批产品时,可以使用简单工厂模式
- 根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。该模式用于封装和管理对象的创建,是一种创建型模式。
如下图,Pizza是一个抽象类,CheessPizza和GreekPizza为实现类,多个OrderPizza可以根据需求创建Pizza对象,然而这种做法在增加新的实现类时,我们要把每个OrderPizza的具体实现都重新更改,十分不合理
如图二,通过简单工厂的方式,我们可以将Pizza作为PizzaFactory的聚合对象,在Factory中调用方法统一创建Pizza对象实例然后返回,每个OrderPizza中聚合了一个Factory对象,直接根据用户输入来调用Factory中的方法来获取 Pizza对象,当增加新的Pizza实现类时,只需要修改Factory中的创建规则,不需要修改每一个OrderPizza
也可以将工厂中的方法定义为静态方法,这样OrderPizza可以直接调用PizzaFactory.getPizza()方法来创建披萨,看需求
2. 工厂方法模式
- 思路:定义一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法模式都将对象的实例化推迟到了子类。
我们将简单工厂中的例子进阶,现在我们不仅有多个种类的披萨,还有多个地区,即北京披萨和天津披萨等,这里简单工厂便不再适用,采取如下的结构,BJOrderPizza和TJOrderPizza就类似于简单工厂,但它们继承于OrderPizza抽象类,该类为一个总的工厂,提供了一个创建pizza实例的抽象方法,由子类各自去实现
3. 抽象工厂模式
- 概念:定义了一个interface用于创建相关或者有依赖关系的对象簇,而无需指明具体的类;可以将抽象工厂模式看成简单工厂和工厂方法的整合
- 将工厂抽象成两层,AbsFactory(抽象工厂 )和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
-
上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品(AbstractProduct),如果要生成另一种产品,应该怎么表示呢?最简单的方式是把2中介绍的工厂方法模式完全复制一份,但同时也就意味着我们要完全复制和修改生产管理的所有代码,显然这是一个笨办法,并不利于扩展和维护。抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。
如下,我们定义一个工厂接口,抽象工厂的好处在于还可以再生产更多的产品,创建好对应的产品,在Factory接口中定义多一个对应的方法,由子类实现,使用方的只需要聚合Factory接口,对应创建工厂实例,就可以创建产品对象;无论时增加新的厂商还是增加新的产品,只需要在提供方增加相应的类,在使用方都是调用Factory接口的方法来实现,则完美遵守开闭原则
- 当只有一种产品时,抽象工厂等于工厂方法,当有多种产品是就不再是工厂方法而是抽象工厂
4. JDK源码示例
简单工厂:Calender对象实例的创建使用了简单工厂
- 说明:外界使用Calender对象时,只需要调用getInstance方法即可获取对应的实例对象,在getInstance方法中,根据传入的后缀不同决定创建的Calender类型。
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
.........................................................
//声明实例对象
Calendar cal = null;
//通过判断传入的后缀来决定创建的实例类型
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
.....................................
}
5. 小结
- 工厂模式的意义:将实例化对象的代码提取出来,放到一个工厂类中进行管理和维护,实现了依赖关系的解耦,提高项目的扩展性和维护性。
- 工厂模式依赖抽象的原则
- 创建对象实例时,不要直接new类,而是要在工厂的方法中new,即变量不要直接持有具体类的引用
- 不要让类直接继承具体类,而是要继承抽象类或者实现接口
- 不要覆盖基类中的方法