阅读本文建议先看下目录,把握整体脉络。最好是使用过工厂模式,即使没有用过该设计模式,文章中的示例建议一定要自己动手敲一敲,便于更加全面深入地了解工厂模式,有异议可以评论或私聊哦
1、简单(静态)工厂模式
1.1 含义
- 简单工厂模式又称静态方式模式(因为工厂类定义了一个静态方法)
- 现实生活中工厂是负责生产产品的;同样在设计模式中,简单工厂模式我们可以理解为负责生产对象的一个类,称为"工厂类"
1.2 解决的问题
将"类实例化的操作"与"使用对象的操作"分开,让使用者不需要知道具体参数就可以实例化出所需要的产品类,从而避免了在客户端代码中显式指定,实现了解耦,即使用者可以直接消费产品而不需要知道其生产的细节
1.3 模式原理
1.3.1 模式组成
1.3.2 UML类图
1.3.3 使用步骤
- 创建抽象产品类,定义具体产品的公共接口
- 创建具体产品类(继承抽象产品类),定义生产的具体产品
- 创建工厂类,通过创建静态方法根据传入不同参数从而创建不同产品类的实例
- 外界调用工厂类的静态方法传入不同参数具体产品类
1.4 实例讲解
1.4.1 需求概况
- 背景:小成有一个塑料生产厂,用来做塑料加工生意
- 目的:最近推出了3个产品,小成希望使用简单工厂模式
1.4.2 使用步骤
创建抽象产品类,定义具体产品类的公共接口
java
package com.zizhou.factory.simple;
/**
* 创建抽象产品类,定义具体产品类的公共接口
*/
public abstract class Product {
public abstract void show();
}
创建具体产品类,继承抽象产品类,定义生产的具体产品
java
// 创建具体产品类,继承抽象产品类,定义生产的具体产品
package com.zizhou.factory.simple;
public class ProductA extends Product{
@Override
public void show() {
System.out.println("ProductA created");
}
}
package com.zizhou.factory.simple;
public class ProductB extends Product{
@Override
public void show() {
System.out.println("ProductB created");
}
}
package com.zizhou.factory.simple;
public class ProductC extends Product{
@Override
public void show() {
System.out.println("ProductC created");
}
}
创建工厂类,通过创建静态方法根据传入的不同参数生成不同具体产品类的实例
java
package com.zizhou.factory.simple;
/**
* 创建工厂类,通过创建静态方法根据传入的不同参数生成不同具体产品类的实例
*/
public class Factory {
public static Product getProduct(String type) {
switch (type) {
case "A":
return new ProductA();
case "B":
return new ProductB();
case "C":
return new ProductC();
default:
return null;
}
}
}
外界调用工厂类的静态方法,传入不同参数生成不同具体产品类的实例
java
package com.zizhou.factory.simple;
/**
* 外界调用工厂类的静态方法,传入不同参数生成不同具体产品类的实例
*/
public class SimpleFactoryTest {
public static void main(String[] args) {
try {
Factory.getProduct("A").show();
} catch (Exception e) {
System.out.println("没有这类产品");
}
try {
Factory.getProduct("B").show();
} catch (Exception e) {
System.out.println("没有这类产品");
}
try {
Factory.getProduct("C").show();
} catch (Exception e) {
System.out.println("没有这类产品");
}
try {
Factory.getProduct("D").show();
} catch (Exception e) {
System.out.println("没有这类产品");
}
}
}
1.5 优点
- 将实例的创建与使用工作分开,使用者不需要关心产品的创建细节,实现了解耦
- 把初始化实例时的工作放到工厂里进行,使代码更容易维护,更符合面向对象原则&面向接口编程,而不是面向实现编程
1.6 缺点
- 工厂类中集中了所有实例的创建逻辑,一旦这个工厂不能工作,整个系统都会受到影响
- 违背了开放-关闭原则,一旦添加新产品就不得不修改工厂类的逻辑,这样会造成工厂逻辑过于复杂
- 简单工厂模式使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构
1.7 使用步骤
- 调用方如果只知道传入工厂类的参数,对于如何创建对象的逻辑并不关心时
- 当工厂类负责创建的对象比较少时
2、工厂方法模式
2.1 介绍
2.1.1 含义
工厂方法模式,又称工厂模式、多态工厂模式或虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类负责生成具体的对象
2.1.2 主要作用
将类实例化(具体产品的创建)的工作延迟给工厂类的子类(具体工厂)中完成,由子类来决定应该实例化(创建)哪一个类
2.1.3 解决的问题
即简单工程模式中的缺点,把具体产品的创建延迟到子类中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂需要实现的接口,这样工厂方式在添加新的产品时不需要修改工厂类的逻辑,而是添加新的工厂子类,符合开放关闭原则,克服了简单工厂模式中的缺点
2.2 模式原理
2.2.1 UML类图
2.2.2 模式组成
2.2.3 使用步骤
- 创建抽象工厂类,定义具体工厂的公共接口
- 创建抽象产品类,定义具体产品的公共接口
- 创建具体产品类,继承抽象产品类,定义生产的具体产品
- 创建具体工厂类,继承抽象工厂类,定义创建具体产品实例的方法
- 外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
2.3 实例讲解
2.3.1 实例概况
- 背景:小成有一间塑料加工厂(仅生产A类产品);随着客户需求的变化,客户需要生产B类产品;
- 冲突:改变原有塑料加工厂的配置和变化非常困难,假设下一次客户需要再发生变化,再次改变将增大非常大的成本;
- 解决方案:小成决定置办塑料分厂B来生产B类产品;
2.3.2 使用步骤
创建抽象工厂类,定义具体工厂的公共接口
java
package com.zizhou.factory.pattern;
/**
* 创建抽象工厂类,定义具体工厂的公共接口
*/
public abstract class Factory {
public abstract Product getProduct();
}
创建抽象产品类,定义具体产品的公共接口
java
package com.zizhou.factory.pattern;
/**
* 创建抽象产品类,定义具体产品的公共接口
*/
public abstract class Product {
public abstract void show();
}
创建具体产品类,继承抽象产品类,描述生产的具体产品
java
package com.zizhou.factory.pattern;
/**
* 创建具体产品类,继承抽象产品类,描述生产的具体产品
*/
public class ProductA extends Product{
@Override
public void show() {
System.out.println("ProductA created");
}
}
package com.zizhou.factory.pattern;
public class ProductB extends Product{
@Override
public void show() {
System.out.println("ProductB created");
}
}
创建具体工厂类, 继承抽象工厂类, 定义创建具体产品实例的方法
java
package com.zizhou.factory.pattern;
/**
* 创建具体工厂类, 继承抽象工厂类, 定义创建具体产品实例的方法
*/
public class FactoryA extends Factory{
@Override
public Product getProduct() {
return new ProductA();
}
}
package com.zizhou.factory.pattern;
public class FactoryB extends Factory{
@Override
public Product getProduct() {
return new ProductB();
}
}
外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
java
package com.zizhou.factory.pattern;
/**
* 外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
*/
public class FactoryPatterTest {
public static void main(String[] args) {
// 产品A
FactoryA factoryA = new FactoryA();
factoryA.getProduct().show();
// 产品B
FactoryB factoryB = new FactoryB();
factoryB.getProduct().show();
}
}
2.4 优点
-
更符合开闭原则
新增一件产品时,只需要增加相应的产品子类和工厂子类即可,简单工厂模式需要修改工厂类的判断逻辑
-
符合单一职责原则
每个具体工厂类只负责创建对应的产品,简单工厂中的工厂类存在复杂的switch逻辑判断
-
不使用静态工厂方法, 可以形成基于继承的等级结构。简单工厂模式的工厂类使用静态工厂方法
总结: 工厂模式可以说是简单工厂模式的进一步抽象和扩展,在保留了简单工厂的封装优点同时,让扩展变得简单,让继承变得可行,增加了多态性的体现
2.5 缺点
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,给系统带来一些额外的开销
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM,反射等技术,增加了系统的实现难度
- 虽然保证了工厂方法的对修改关闭原则,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类
- 一个具体工厂只能创建一个具体产品
2.6 应用场景
- 当一个类不知道它所需要的对象的类时
在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道对应的工厂即可 - 当一个类需要通过子类来指定创建对象时
在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏替换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展 - 将创建对象的任务委托给多个工厂子类中的一个,客户端在使用时可以无需关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或者数据库中
3、抽象工厂模式
3.1 定义
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口
3.2 产品等级和产品族
- 产品等级:即是相同的产品,例如美的冰箱、海尔冰箱、格力冰箱,他们都是冰箱,他们的产品等级都相同,虽然不属于同一个厂家
- 产品族:即是相同的厂家,美的冰箱、美的空调、美的电扇,他们虽然不是同一个产品等级,但属于同一个厂家,所以他们的产品族相同
3.3 抽象工厂和抽象方法的区别
抽象工厂是创建型设计模式,他强调了一系列产品对象(即属于同一个产品族)的创建过程,和工厂方法侧重点不同,工厂方法更侧重于同一产品等级,而抽象工厂侧重的是同一产品族
3.4 使用步骤
- 创建产品接口,定义产品信息方法
- 创建具体产品, 实现产品接口,描述具体产品的信息
- 创建抽象工厂接口,提供创建具体产品实例的方法
- 创建具体的工厂, 实现抽象工厂接口
- 外界调用工厂中提供的方法, 创建具体产品
3.5 实例概况
创建产品接口,描述产品信息
java
package com.zizhou.factory.abstractly;
/**
* 创建产品接口,描述产品信息
*/
public interface AirConditioner {
void airConditionInfo();
}
package com.zizhou.factory.abstractly;
public interface Fan {
void fanInfo();
}
package com.zizhou.factory.abstractly;
public interface Fridge {
void fridgeInfo();
}
创建具体产品, 实现产品接口,描述具体产品的信息
java
package com.zizhou.factory.abstractly;
/**
* 创建具体产品, 实现产品接口,描述具体产品的信息
*/
public class MediaAirConditioner implements AirConditioner{
@Override
public void airConditionInfo() {
System.out.println("美的空调");
}
}
package com.zizhou.factory.abstractly;
public class MediaFan implements Fan{
@Override
public void fanInfo() {
System.out.println("美的电风扇");
}
}
package com.zizhou.factory.abstractly;
public class MediaFridge implements Fridge{
@Override
public void fridgeInfo() {
System.out.println("美的冰箱");
}
}
创建抽象工厂接口,提供创建具体产品实例的方法
java
package com.zizhou.factory.abstractly;
/**
* 创建抽象工厂接口,提供创建具体产品实例的方法
*/
public interface Factory {
AirConditioner createAirConditioner();
Fridge createFridge();
Fan createFan();
}
package com.zizhou.factory.abstractly;
/**
* 创建具体的工厂, 实现抽象工厂接口
*/
public class MediaFactory implements Factory{
@Override
public AirConditioner createAirConditioner() {
return new MediaAirConditioner();
}
@Override
public Fridge createFridge() {
return new MediaFridge();
}
@Override
public Fan createFan() {
return new MediaFan();
}
}
外界调用工厂中提供的方法, 创建具体产品
java
/**
* 外界调用工厂中提供的方法, 创建具体产品
*/
public class AbstractlyTest {
public static void main(String[] args) {
Factory factory = new MediaFactory();
factory.createAirConditioner().airConditionInfo();
factory.createFridge().fridgeInfo();
factory.createFan().fanInfo();
}
}
3.6 优点
- 可以确信你从工厂得到的产品彼此是兼容的
- 可以避免具体产品和客户端代码之间的紧密耦合
- 符合单一职责原则
- 符合开闭原则
3.7应用场景
程序需要处理不同系列的相关产品,但是您不需要依赖于这些产品的具体类时,可以使用抽象工厂模式