【设计模式】工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)详记

注:本文仅供学习参考,如有错漏还请指正!

参考文献/文章地址:

  • 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

  • 《设计模式:可复用面向对象软件的基础》(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种设计模式及其分类

创建范例

创建范例全部是关于如何创建实例的。这组范例可以被划分为两组:类创建范例及对象创建范例。类创建实例在实例化过程中有效的使用类之间的继承关系,对象创建范例则使用代理来完成其任务。

结构范例

这组范例都是关于类及对象复合关系的。

行为范例

这组范例都是关于对象之间如何通讯的。

二、简单工厂模式(工厂方法的特殊形式)

2.1 模式定义

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

2.2 模式结构

  • Factory:工厂角色

    工厂角色负责实现创建所有实例的内部逻辑

  • Product:抽象产品角色

    抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口

  • ConcreteProduct:具体产品角色

    具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

2.3 类图

../_images/SimpleFactory.jpg

2.4 具体实现

目录结构如下:

image-20230625163639652

抽象产品角色:

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();
    }
}

测试结果:

image-20230625164026077

2.5 简单工厂模式的优缺点

优点:

客户端程序不需要关心对象的创建细节,需要哪个对象时,只需要向工厂索要即可,初步实现了责任的分离。客户端只负责“消费”, 工厂负责“生产”。生产和消费分离。

缺点:

  • 工厂类集中了所有的逻辑创造,形成一个无所不知的全能类,有人把它叫做上帝类。显然工厂类非常关键,一旦出问题则整个系统瘫痪。
  • 简单工厂模式违反了开闭原则(OCP原则),在进行系统扩展时,需要修改工厂类。

三、工厂方法模式

3.1 模式定义

工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

3.2 模式结构

  • 产品 (Product) 将会对接口进行声明。 对于所有由创建者及其子类构建的对象, 这些接口都是通用的。

  • 具体产品 (Concrete Products) 是产品接口的不同实现。

  • 创建者 (Creator) 类声明返回产品对象的工厂方法。 该方法的返回对象类型必须与产品接口相匹配。

    你可以将工厂方法声明为抽象方法, 强制要求每个子类以不同方式实现该方法。 或者, 你也可以在基础工厂方法中返回默认产品类型。

    注意, 尽管它的名字是创建者, 但它最主要的职责并不是创建产品。 一般来说, 创建者类包含一些与产品相关的核心业务逻辑。 工厂方法将这些逻辑处理从具体产品类中分离出来。 打个比方, 大型软件开发公司拥有程序员培训部门。 但是, 这些公司的主要工作还是编写代码, 而非生产程序员。

  • 具体创建者 (Concrete Creators) 将会重写基础工厂方法, 使其返回不同类型的产品。

    注意, 并不一定每次调用工厂方法都会创建新的实例。 工厂方法也可以返回缓存、 对象池或其他来源的已有对象。

3.3 类图

工厂方法模式结构

3.4 具体实现

目录结构如下:

image-20230625171106704

产品(抽象产品):

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();
    }
}

测试结果:

image-20230625171503377

3.5 工厂方法模式的优缺点

优点:

  • 你可以避免创建者和具体产品之间的紧密耦合。
  • 单一职责原则。 你可以将产品创建代码放在程序的单一位置, 从而使得代码更容易维护。
  • 开闭原则。 无需更改现有客户端代码, 你就可以在程序中引入新的产品类型。

缺点:

应用工厂方法模式需要引入许多新的子类, 代码可能会因此变得更复杂。 最好的情况是将该模式引入创建者类的现有层次结构中。

四、抽象工厂模式

4.1 模式定义

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

4.2 模式结构

  • 抽象产品 (Abstract Product) 为构成系列产品的一组不同但相关的产品声明接口。
  • 具体产品 (Concrete Product) 是抽象产品的多种不同类型实现。 所有变体 (维多利亚/现代) 都必须实现相应的抽象产品 (椅子/沙发)。
  • 抽象工厂 (Abstract Factory) 接口声明了一组创建各种抽象产品的方法。
  • 具体工厂 (Concrete Factory) 实现抽象工厂的构建方法。 每个具体工厂都对应特定产品变体, 且仅创建此种产品变体。

4.3 类图

../_images/AbatractFactory.jpg

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();
    }
}

运行结果:

image-20230625175006770

4.5 抽象工厂模式的优缺点

优点:

当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:

产品族扩展非常困难,要增加一个系列的某一产品,既要在AbstractFactory里加代码,又要在具体的里面加代码。

猜你喜欢

转载自blog.csdn.net/m0_47015897/article/details/131387369