注:本文仅供学习参考,如有错漏还请指正!
参考文献/文章地址:
https://zh.wikipedia.org/wiki/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%EF%BC%9A%E5%8F%AF%E5%A4%8D%E7%94%A8%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%BD%AF%E4%BB%B6%E7%9A%84%E5%9F%BA%E7%A1%80
https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/simple_factory.html
https://refactoringguru.cn/design-patterns/abstract-factory
文章目录
- 一、关于GoF
- 23种设计模式及其分类
- 创建范例
- 结构范例
- 行为范例
- 二、简单工厂模式(工厂方法的特殊形式)
- 2.1 模式定义
- 2.2 模式结构
- 2.3 类图
- 2.4 具体实现
- 2.5 简单工厂模式的优缺点
- 三、工厂方法模式
- 3.1 模式定义
- 3.2 模式结构
- 3.3 类图
- 3.4 具体实现
- 3.5 工厂方法模式的优缺点
- 四、抽象工厂模式
- 4.1 模式定义
- 4.2 模式结构
- 4.3 类图
- 4.4 具体实现
- 4.5 抽象工厂模式的优缺点
一、关于GoF
-
《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software)是软件工程领域有关设计模式的一本书,提出和总结了对于一些常见软件设计问题的标准解决方案,称为软件设计模式。该书作者是埃里希·伽玛(Erich Gamma)、Richard Helm、Ralph Johnson和John Vlissides,后以“四人帮”(Gang of Four,GoF)著称,书中的设计模式也被称为“四人帮设计模式”(Gang of Four design patterns)。
-
该书中描述了23种设计模式。我们平常所说的设计模式就是指这23种设计模式。
-
不过除了GoF23种设计模式之外,还有其它的设计模式,比如:JavaEE的设计模式(DAO模式、MVC模式等)。
23种设计模式及其分类
创建范例
创建范例全部是关于如何创建实例的。这组范例可以被划分为两组:类创建范例及对象创建范例。类创建实例在实例化过程中有效的使用类之间的继承关系,对象创建范例则使用代理来完成其任务。
- 抽象工厂 (Abstract Factory)
- 构造器 (Builder Pattern)
- 工厂方法 (Factory Method pattern)
- 原型 (Prototype pattern)
- 单例模式 (Singleton pattern)
结构范例
这组范例都是关于类及对象复合关系的。
- 适配器(Adapter pattern)
- 桥接(Bridge pattern)
- 组合(Composite pattern)
- 装饰(Decorator pattern)
- 外观(Facade pattern)
- 享元(Flyweight pattern)
- 代理(Proxy pattern)
行为范例
这组范例都是关于对象之间如何通讯的。
- 责任链(Chain-of-responsibility pattern)
- 命令(Command pattern)
- 翻译器(Interpreter pattern)
- 迭代器(Iterator pattern)
- 中介者(Mediator pattern)
- 回忆(Memento pattern)
- 观察者(Observer pattern)
- 状态机(State pattern)
- 策略(Strategy pattern)
- 模板方法(Template method pattern)
- 参观者(Visitor)
二、简单工厂模式(工厂方法的特殊形式)
2.1 模式定义
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
2.2 模式结构
-
Factory:工厂角色
工厂角色负责实现创建所有实例的内部逻辑
-
Product:抽象产品角色
抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
-
ConcreteProduct:具体产品角色
具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
2.3 类图
2.4 具体实现
目录结构如下:
抽象产品角色:
package *com.hzzlovezq.abstractProduct*;
public abstract class Fruit {
public abstract void sell();
}
具体产品角色:
package com.hzzlovezq.specificProduct;
import com.hzzlovezq.abstractProduct.Fruit;
public class Banana extends Fruit {
@Override
public void sell() {
System.out.println("出售一个香蕉~");
}
}
package com.hzzlovezq.specificProduct;
import com.hzzlovezq.abstractProduct.Fruit;
public class Orange extends Fruit {
@Override
public void sell() {
System.out.println("出售一个橙子~");
}
}
工厂角色:
package com.hzzlovezq.factory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificProduct.Banana;
import com.hzzlovezq.specificProduct.Orange;
public class FruitFactory {
public static Fruit getFruit(String fruitType){
if ("ORANGE".equals(fruitType)) {
return new Orange();
} else if ("BANANA".equals(fruitType)){
return new Banana();
} else {
throw new RuntimeException("本店不出售该水果!");
}
// return null;
}
}
测试代码:
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.factory.FruitFactory;
import org.junit.Test;
public class SimpleFactoryTest {
@Test
public void testSell(){
Fruit orange = FruitFactory.getFruit("ORANGE");
orange.sell();
Fruit banana = FruitFactory.getFruit("BANANA");
banana.sell();
}
}
测试结果:
2.5 简单工厂模式的优缺点
优点:
客户端程序不需要关心对象的创建细节,需要哪个对象时,只需要向工厂索要即可,初步实现了责任的分离。客户端只负责“消费”, 工厂负责“生产”。生产和消费分离。
缺点:
- 工厂类集中了所有的逻辑创造,形成一个无所不知的全能类,有人把它叫做上帝类。显然工厂类非常关键,一旦出问题则整个系统瘫痪。
- 简单工厂模式违反了开闭原则(OCP原则),在进行系统扩展时,需要修改工厂类。
三、工厂方法模式
3.1 模式定义
工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
3.2 模式结构
-
产品 (Product) 将会对接口进行声明。 对于所有由创建者及其子类构建的对象, 这些接口都是通用的。
-
具体产品 (Concrete Products) 是产品接口的不同实现。
-
创建者 (Creator) 类声明返回产品对象的工厂方法。 该方法的返回对象类型必须与产品接口相匹配。
你可以将工厂方法声明为抽象方法, 强制要求每个子类以不同方式实现该方法。 或者, 你也可以在基础工厂方法中返回默认产品类型。
注意, 尽管它的名字是创建者, 但它最主要的职责并不是创建产品。 一般来说, 创建者类包含一些与产品相关的核心业务逻辑。 工厂方法将这些逻辑处理从具体产品类中分离出来。 打个比方, 大型软件开发公司拥有程序员培训部门。 但是, 这些公司的主要工作还是编写代码, 而非生产程序员。
-
具体创建者 (Concrete Creators) 将会重写基础工厂方法, 使其返回不同类型的产品。
注意, 并不一定每次调用工厂方法都会创建新的实例。 工厂方法也可以返回缓存、 对象池或其他来源的已有对象。
3.3 类图
3.4 具体实现
目录结构如下:
产品(抽象产品):
package *com.hzzlovezq.abstractProduct*;
public abstract class Fruit {
public abstract void sell();
}
具体产品:
package com.hzzlovezq.specificProduct;
import com.hzzlovezq.abstractProduct.Fruit;
public class Banana extends Fruit {
@Override
public void sell() {
System.out.println("Sold a banana~");
}
}
package com.hzzlovezq.specificProduct;
import com.hzzlovezq.abstractProduct.Fruit;
public class Orange extends Fruit {
@Override
public void sell() {
System.out.println("Sold an orange~");
}
}
package com.hzzlovezq.specificProduct;
import com.hzzlovezq.abstractProduct.Fruit;
public class Apple extends Fruit {
@Override
public void sell() {
System.out.println("Sold an apple~");
}
}
创建者(抽象工厂):
package com.hzzlovezq.abstractFactory;
import com.hzzlovezq.abstractProduct.Fruit;
public interface FruitFactory {
Fruit getFruit();
}
具体创建者(具体工厂):
package com.hzzlovezq.specificFactory;
import com.hzzlovezq.abstractFactory.FruitFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificProduct.Banana;
public class BananaFactory implements FruitFactory {
@Override
public Fruit getFruit() {
return new Banana();
}
}
package com.hzzlovezq.specificFactory;
import com.hzzlovezq.abstractFactory.FruitFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificProduct.Orange;
public class OrangeFactory implements FruitFactory {
@Override
public Fruit getFruit() {
return new Orange();
}
}
package com.hzzlovezq.specificFactory;
import com.hzzlovezq.abstractFactory.FruitFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificProduct.Apple;
public class AppleFactory implements FruitFactory {
@Override
public Fruit getFruit() {
return new Apple();
}
}
测试代码:
import com.hzzlovezq.abstractFactory.FruitFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.specificFactory.AppleFactory;
import com.hzzlovezq.specificFactory.BananaFactory;
import com.hzzlovezq.specificFactory.OrangeFactory;
import org.junit.Test;
public class MethodFactoryTest {
@Test
public void methodTest(){
FruitFactory bananaFactory = new BananaFactory();
Fruit banana = bananaFactory.getFruit();
banana.sell();
FruitFactory orangeFactory = new OrangeFactory();
Fruit orange = orangeFactory.getFruit();
orange.sell();
FruitFactory appleFactory = new AppleFactory();
Fruit apple = appleFactory.getFruit();
apple.sell();
}
}
测试结果:
3.5 工厂方法模式的优缺点
优点:
- 你可以避免创建者和具体产品之间的紧密耦合。
- 单一职责原则。 你可以将产品创建代码放在程序的单一位置, 从而使得代码更容易维护。
- 开闭原则。 无需更改现有客户端代码, 你就可以在程序中引入新的产品类型。
缺点:
应用工厂方法模式需要引入许多新的子类, 代码可能会因此变得更复杂。 最好的情况是将该模式引入创建者类的现有层次结构中。
四、抽象工厂模式
4.1 模式定义
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
4.2 模式结构
- 抽象产品 (Abstract Product) 为构成系列产品的一组不同但相关的产品声明接口。
- 具体产品 (Concrete Product) 是抽象产品的多种不同类型实现。 所有变体 (维多利亚/现代) 都必须实现相应的抽象产品 (椅子/沙发)。
- 抽象工厂 (Abstract Factory) 接口声明了一组创建各种抽象产品的方法。
- 具体工厂 (Concrete Factory) 实现抽象工厂的构建方法。 每个具体工厂都对应特定产品变体, 且仅创建此种产品变体。
4.3 类图
4.4 具体实现
目录结构如下:
抽象工厂:
package *com.hzzlovezq.abstractFactory*;
import *com.hzzlovezq.abstractProduct.*Fruit;
import *com.hzzlovezq.abstractProduct.*Weapon;
public abstract class AbstractFactory {
public abstract Fruit getFruit(*String* *fruitType*);
public abstract Weapon getWeapon(*String* *weaponType*);
}
具体工厂:
package com.hzzlovezq.concreteFactory;
import com.hzzlovezq.abstractFactory.AbstractFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.abstractProduct.Weapon;
import com.hzzlovezq.concreteProduct.Apple;
import com.hzzlovezq.concreteProduct.Orange;
public class FruitFactory extends AbstractFactory {
@Override
public Fruit getFruit(String fruitType) {
if ("ORANGE".equals(fruitType)) {
return new Orange();
} else if ("APPLE".equals(fruitType)) {
return new Apple();
} else {
throw new RuntimeException("不出售该类水果!");
}
}
@Override
public Weapon getWeapon(String weaponType) {
return null;
}
}
package com.hzzlovezq.concreteFactory;
import com.hzzlovezq.abstractFactory.AbstractFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.abstractProduct.Weapon;
import com.hzzlovezq.concreteProduct.Apple;
import com.hzzlovezq.concreteProduct.Dagger;
import com.hzzlovezq.concreteProduct.Gun;
import com.hzzlovezq.concreteProduct.Orange;
public class WeaponFactory extends AbstractFactory {
@Override
public Fruit getFruit(String fruitType) {
return null;
}
@Override
public Weapon getWeapon(String weaponType) {
if ("GUN".equals(weaponType)) {
return new Gun();
} else if ("DAGGER".equals(weaponType)) {
return new Dagger();
} else {
throw new RuntimeException("不出售该类水果!");
}
}
}
抽象产品:
package com.hzzlovezq.abstractProduct;
public abstract class Fruit {
public abstract void sell();
}
package com.hzzlovezq.abstractProduct;
public abstract class Weapon {
public abstract void attack();
}
具体产品:
package com.hzzlovezq.concreteProduct;
import com.hzzlovezq.abstractProduct.Weapon;
public class Gun extends Weapon {
@Override
public void attack() {
System.out.println("给你一梭子~");
}
}
package com.hzzlovezq.concreteProduct;
import com.hzzlovezq.abstractProduct.Weapon;
public class Dagger extends Weapon {
@Override
public void attack() {
System.out.println("戳死你~");
}
}
package com.hzzlovezq.concreteProduct;
import com.hzzlovezq.abstractProduct.Fruit;
public class Apple extends Fruit {
@Override
public void sell() {
System.out.println("卖了一个苹果~");
}
}
package com.hzzlovezq.concreteProduct;
import com.hzzlovezq.abstractProduct.Fruit;
public class Orange extends Fruit {
@Override
public void sell() {
System.out.println("卖了一个橙子~");
}
}
测试代码:
import com.hzzlovezq.abstractFactory.AbstractFactory;
import com.hzzlovezq.abstractProduct.Fruit;
import com.hzzlovezq.abstractProduct.Weapon;
import com.hzzlovezq.concreteFactory.FruitFactory;
import com.hzzlovezq.concreteFactory.WeaponFactory;
import org.junit.Test;
public class AbstractFactoryTest {
@Test
public void abstractTest(){
// 客户端调用方法时只面向AbstractFactory调用方法。
AbstractFactory factory = new WeaponFactory(); // 注意:这里的new WeaponFactory()可以采用 简单工厂模式 进行隐藏。
Weapon gun = factory.getWeapon("GUN");
Weapon dagger = factory.getWeapon("DAGGER");
gun.attack();
dagger.attack();
AbstractFactory factory1 = new FruitFactory(); // 注意:这里的new FruitFactory()可以采用 简单工厂模式 进行隐藏。
Fruit orange = factory1.getFruit("ORANGE");
Fruit apple = factory1.getFruit("APPLE");
orange.sell();
apple.sell();
}
}
运行结果:
4.5 抽象工厂模式的优缺点
优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:
产品族扩展非常困难,要增加一个系列的某一产品,既要在AbstractFactory里加代码,又要在具体的里面加代码。