工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。该模式用于封装和管理对象的创建,是一种创建型模式。
简单工厂模式
该模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象,其UML类图如下:
抽象产品和实现:
public interface Product {
void doSomething();
void doAnything();
}
public class ConcreteProductA implements Product {
@Override
public void doSomething() {
System.out.println("ConcreteProductA doSomething");
}
@Override
public void doAnything() {
System.out.println("ConcreteProductA doAnything");
}
}
public class ConcreteProductB implements Product {
@Override
public void doSomething() {
System.out.println("ConcreteProductB doSomething");
}
@Override
public void doAnything() {
System.out.println("ConcreteProductB doAnything");
}
}
工厂类:
public class Creator {
public static Product createProduct(String type) {
Product product = null;
switch (type) {
case "A":
product = new ConcreteProductA();
break;
case "B":
product = new ConcreteProductB();
break;
}
return product;
}
}
测试:
public class Client {
public static void main(String[] args) {
Product productA = Creator.createProduct("A");
productA.doSomething();
productA.doAnything();
Product productB = Creator.createProduct("B");
productB.doSomething();
productB.doAnything();
}
}
优点:
- 客户端不需要依赖具体的产品类,只依赖工厂类,传入不同的参数就可以得到不同的对象
缺点:
- 工厂类的扩展比较困难,每增加一个产品,就要在工厂中添加相应的分支,对扩展开放的同时对修改也开放了,不符合开闭原则
使用场景:
- 产品种类较少,并且种类需求已确定,比如计算器,已知的运算类型较少并且具体由多少种类型是已知的
工厂方法模式
和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂。也就是定义一个抽象工厂,其定义了产品的生产接口,但不负责具体的产品,将生产任务交给不同的派生类工厂,这样不用通过指定类型来创建对象了。其UML类图如下:
抽象产品和实现同简单工厂模式
抽象工厂类:
public interface Creator {
Product createProduct();
}
具体工厂类-生产A产品的工厂:
public class ConcreteCreatorA implements Creator {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
具体工厂类-生产B产品的工厂:
public class ConcreteCreatorB implements Creator {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
测试:
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
Product productA = creatorA.createProduct();
productA.doSomething();
productA.doAnything();
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.createProduct();
productB.doSomething();
productB.doAnything();
}
优点:
- 良好的封装性,代码结构清晰
- 工厂方法模式的扩展性好
增加产品类的时候,不用去修改原有工厂类的逻辑,而是直接新建一个工厂类的实现即可
降低程序间的耦合性
缺点:
每增加一个产品类,就需要增加一个对应的工厂类,增加了额外的开发量
扩展
利用反射机制来解决"每增加一个产品类,就需要增加一个对应的工厂类"的问题
抽象工厂类:
public interface Creator {
<T extends Product> T createProduct(Class<T> clazz);
}
具体工厂类:
public class ConcreteCreator implements Creator {
@Override
public <T extends Product> T createProduct(Class<T> clazz) {
Product product= null;
try {
product = (Product) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return (T) product;
}
}
测试:
public class Client {
public static void main(String[] args) {
Creator creator = new ConcreteCreator();
Product productA = creator.createProduct(ConcreteProductA.class);
productA.doSomething();
productA.doAnything();
Product productB = creator.createProduct(ConcreteProductB.class);
productB.doSomething();
productB.doAnything();
}
}
小结
工厂方法模式是对简单工厂模式的进一步抽象和解耦,避免了简单工厂违背开闭原则的缺点,利用反射机制提高开发效率。
抽象工厂模式
UML如下:
抽象产品A接口:
public interface ProductA {
void doSomething();
void doAnything();
}
抽象产品B接口:
public interface ProductB {
void doSomething();
void doAnything();
}
产品A1的具体实现:
public class ConcreteProductA1 implements ProductA {
@Override
public void doSomething() {
System.out.println("ConcreteProductA1 doSomething");
}
@Override
public void doAnything() {
System.out.println("ConcreteProductA1 doAnything");
}
}
产品A2的具体实现:
public class ConcreteProductA2 implements ProductA {
@Override
public void doSomething() {
System.out.println("ConcreteProductA2 doSomething");
}
@Override
public void doAnything() {
System.out.println("ConcreteProductA2 doAnything");
}
}
产品B1的具体实现:
public class ConcreteProductB1 implements ProductB {
@Override
public void doSomething() {
System.out.println("ConcreteProductB1 doSomething");
}
@Override
public void doAnything() {
System.out.println("ConcreteProductB1 doAnything");
}
}
产品B2的具体实现:
public class ConcreteProductB2 implements ProductB {
@Override
public void doSomething() {
System.out.println("ConcreteProductB2 doSomething");
}
@Override
public void doAnything() {
System.out.println("ConcreteProductB2 doAnything");
}
}
抽象工厂类:
public interface Creator {
/**
* 创建A产品家族
* @return
*/
ProductA createProductA();
/**
* 创建B产品家族
* @return
*/
ProductB createProductB();
// ...
// 有N个产品族,在抽象工厂类中就应该有N个创建方法
}
具体工厂类:
public class ConcreteCreator1 implements Creator {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
public class ConcreteCreator2 implements Creator {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
//产品种类有多少个,就有多少个实现类
客户端:
public class Client {
public static void main(String[] args) {
Creator creator1 = new ConcreteCreator1();
ProductA productA1 = creator1.createProductA();
productA1.doSomething();
productA1.doAnything();
ProductB productB1 = creator1.createProductB();
productB1.doSomething();
productB1.doAnything();
Creator creator2 = new ConcreteCreator2();
ProductA productA2 = creator2.createProductA();
productA2.doSomething();
productA2.doAnything();
ProductB productB2 = creator2.createProductB();
productB2.doSomething();
productB2.doAnything();
}
}
JDK源码中的简单抽象工厂模式
jdk8
Calendar
类对象的创建就使用了简单抽象工厂模式,对Calendar cal = Calendar.getInstance();
这段代码,进入getInstance()
方法内部:
public static Calendar getInstance()
{
//TimeZone就相当于一个工厂类,getDefault()用于获取实例化对象
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
再进入getDefault()
方法内部:
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
//这里就是一个简单工厂模式,根据caltype值的不同返回不同的实例对象
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;
}
}
}
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}
总结
- 工厂模式的意义就在于将实例化对象的代码提取出来,放到一个类(工厂类)中统一管理和维护,达到和主项目依赖关系的解耦,从而提高项目的扩展和维护性。
设计模式中依赖抽象的原则:
- 创建对象的时候,不要在客户端直接使用
new
,而是把实例化对象的过程放在一个工厂类中 - 不要让类继承具体类,而是继承抽象类或者实现接口
- 不要覆盖类中已经实现的方法