设计模式 - 工厂模式

工厂模式是创建型模式之一,其主要功能都是帮助我们把对象的实例化部分分离出来,降低系统中代码耦合度,增强了系统的扩展性,并将对象的创建过程延迟到子类进行

工厂模式

分类:

  • 简单工厂模式(Simple Factory):只有一个工厂,通过向工厂传参来选择工厂所要生产的产品
  • 工厂方法模式(Factory Method):允许多个工厂,但一个工厂只生产一种产品,通过不同的工厂类型来选择所要生产的产品
  • 抽象工厂模式(Abstract Factory):允许多个工厂,一个工厂允许生产多种产品,通过工厂实例的不同方法来选择所要生产的产品

Github源码:

简单工厂模式

含义:只有一个工厂类,客户端向工厂传递所需产品名,工厂生产产品交予客户

实现过程:

  • 理论性:创建产品的抽象类做为产品基类,产品类(派生类)继承该基类并实现各自方法。工厂类 负责接收客户端传入的参数(产品名),根据参数选择对应产品类进行实例化,最终返回给客户端
  • 比喻:客户去印刷厂印刷书籍,客户只需要告诉印刷厂其需求(书名、材质 ..),印刷厂根据该需求选择印刷对应的书籍,最终交予客户

优缺点:

  • 优点:
    • 客户端无须知道所创建的具体产品类的创建细节,只需将产品名参数传递到工厂类即可实现创建并使用
    • 添加新类即可实现新产品的类,无需对客户端进行大改动
  • 缺点:
    • 随着产品的增加,对应产品类数量增加,增加了系统复杂度
    • 新增加产品类都会修改工厂类,违背 “开闭原则”
    • 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响

项目示例:

简单工厂模式实现加减乘除运算,工厂类OperationFactory 根据传入的运算符字符("+"、"-" ..),自动选择实例化的运算类并返回,实现计算:

// 运算基类(抽象产品类):
// --------------------
public class Operation
{
    public double NumberA { get; set; }
    public double NumberB { get; set; }

    public virtual double GetResult()
    {
        double result = 0;
        return result;
    }
}

// 运算符派生类(具体产品类):
// ------------------------
class OperationAdd : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberA + NumberB;
        return result;
    }
}
class OperationSub : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberA - NumberB;
        return result;
    }
}
class OperationMul : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberA * NumberB;
        return result;
    }
}
class OperationDiv : Operation
{
    public override double GetResult()
    {
        double result = 0;
        if (NumberB == 0)
            throw new Exception("除数不可为 0");
        result = NumberA / NumberB;
        return result;
    }
}

// 工厂类:
// ------
public class OperationFactory
{
    public static Operation CreateOperate(string operate)
    {
        //根据传入的参数operate选择实例化的类
        Operation oper = null;
        switch (operate)
        {
            case "+":
                oper = new OperationAdd();
                break;
            case "-":
                oper = new OperationSub();
                break;
            case "*":
                oper = new OperationMul();
                break;
            case "/":
                oper = new OperationDiv();
                break;
        }
        return oper;
    }
}

// 客户端:
// ------
class Test
{
    static void Main(string[] args)
    {
		//创建运算基类的对象,传入字符串到工厂类,返回对应实类的实例对象
        Operation oper;        
        oper = OperationFactory.CreateOperate("+");
        oper.NumberA = 4;  oper.NumberB = 2;
        double result = oper.GetResult();
        Console.WriteLine(result);		// 6

        oper = OperationFactory.CreateOperate("-");
        oper.NumberA = 4; oper.NumberB = 2;
        result = oper.GetResult();
        Console.WriteLine(result);		// 2

        oper = OperationFactory.CreateOperate("/");
        oper.NumberA = 4; oper.NumberB = 2;
        result = oper.GetResult();
        Console.WriteLine(result);		// 2
    }
}

UML图

工厂方法模式

含义:允许多个工厂,但一个工厂只生产一种产品,通过不同的工厂类型来选择所要生产的产品。也可以说:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,即使其创建过程延迟到子类进行

实现过程:

  • 理论性:创建抽象工厂接口,创建各类产品的工厂类继承该接口并实现各自方法。客户端选择所需产品的工厂,对应工厂实现生产并返还
  • 比喻:客户去印刷全彩书刊,需要找到对应的全彩书刊印刷厂,该工厂拥有印刷该类书籍的方法,因此可执行印刷功能并将产品交予客户

优缺点:

  • 优点:
    • 用户只需关心产品对应工厂而无需知道创建细节、产品名
    • 添加新产品只需添加具体工厂类、产品类即可,可拓展性好,符合 “开放封闭原则”
    • 由于一个工厂只生产一种产品,因此也符合“单一职责原则”
  • 缺点:
    • 随着产品的增加,对应工厂类、产品类数量增加,增加了系统复杂度

项目示例:

对上节简单工厂方法的项目示例做修改,实现工厂方法模式:抽象产品类、各运算类保持不变,添加抽象工厂接口,并由该接口派生出各类计算方法的工厂类,客户端通过工厂类即可实现计算功能

#region 上述的运算基类(抽象产品类) + 运算符派生类(具体产品类)
//...
#endregion

// 抽象工厂接口:
// -----------
interface IFactory
{
    Operation CreateOperation();
}

// 各运算工厂类:
// -----------
// 加法工厂
class AddFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationAdd();
    }
}
// 减法工厂
class SubFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationSub();
    }
}
// 乘法工厂
class MulFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationMul();
    }
}
// 除法工厂
class DivFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationDiv();
    }
}

// 客户端:
// ------
class Test
{
    static void Main(string[] args)
    {
		//用户选择产品对应的工厂进行生产
        IFactory operFactory = new AddFactory();
        Operation oper = operFactory.CreateOperation();
        oper.NumberA = 4;   oper.NumberB = 2;
        double result = oper.GetResult();		//6
    }
}

UML图

抽象工厂模式

含义:允许多个工厂,一个工厂允许生产多种产品,通过工厂实例的不同方法来选择所要生产的产品。也可以说:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类

实现过程:

  • 理论性:抽象产品接口->具体产品类,抽象工厂接口->具体工厂类,客户端创建工厂、选择生产产品
  • 比喻:显示器(抽象产品接口)的产品有苹果显示器、戴尔显示器(具体产品类),主机的产品也有苹果和戴尔;生产电脑设备的工厂(抽象工厂接口)有苹果工厂和戴尔工厂(具体工厂类),客户可以选择苹果或者戴尔电脑工厂,再选择要生产该品牌的显示器或是主机

扩展:

  • 产品族:具有相同属性的同类型产品,如戴尔显示器、戴尔主机都属于戴尔
  • 产品等级结构:产品的继承结构,如产品抽象类(显示器),其具体产品类有戴尔显示器、苹果显示器,抽象类与产品类之间构成了产品等级结构

优缺点:

  • 优点:
    • 将一个系列的产品族(戴尔的显示器、主机..)统一到对应工厂进行创建,便于客户端直接使用同一产品族的工厂进行生产操作
    • 较比与工厂方法模式,减少了工厂类和具体产品的类添加
  • 缺点:
    • 产品族扩展困难(例如添加苹果ipad,则需要对产品的抽象、具体类修改,工厂的抽象、具体类修改)

项目示例:

采用抽象工厂模式实现苹果、戴尔电脑的生产工厂:创建两个抽象产品接口(显示器、主机),根据该接口实现具体产品类(苹果显示器、苹果主机、戴尔..);创建抽象工厂接口(电脑工厂),根据该接口实现具体工厂类(苹果电脑工厂、戴尔电脑工厂);最终在客户端进行工厂创建、生产产品

// 抽象产品类:
// ----------
// 抽象产品 - 显示器
interface IDisplay
{
    void Show();
}
// 抽象产品 - 主机
interface IMainFrame
{
    void Open();
}

// 具体产品类:
// ----------
// 具体产品 - 苹果显示器
class AppleDisplay : IDisplay
{
    public void Show()
    {
        Console.WriteLine("苹果显示器正常工作!");
    }
}
//具体产品 - 戴尔显示器
class DellDisplay : IDisplay
{
    public void Show()
    {
        Console.WriteLine("戴尔显示器正常工作!");
    }
}
// 具体产品 - 苹果主机
class AppleMainFrame : IMainFrame
{
    public void Open()
    {
        Console.WriteLine("苹果主机启动成功!");
    }
}
// 具体产品 - 戴尔主机
class DellMainFrame : IMainFrame
{
    public void Open()
    {
        Console.WriteLine("戴尔主机启动成功!");
    }
}

// 抽象工厂类:
// ----------
// 抽象电脑工厂
interface IComputerFactory
{
    // 生产一个显示器
    IDisplay ProduceADisplay();

    // 生产一个主机
    IMainFrame ProduceAMainFrame();
}

// 具体工厂类:
// ----------
// 具体工厂 - 苹果电脑工厂
class AppleComputerFactory:IComputerFactory
{
    public IDisplay ProduceADisplay()
    {
        return new AppleDisplay();
    }

    public IMainFrame ProduceAMainFrame()
    {
        return new AppleMainFrame();
    }
}
// 具体工厂 - 戴尔电脑工厂
class DellComputerFactory : IComputerFactory
{
    public IDisplay ProduceADisplay()
    {
        return new DellDisplay();
    }

    public IMainFrame ProduceAMainFrame()
    {
        return new DellMainFrame();
    }
}

// 客户端:
// ------
class Client
{
    static void Main()
    {
        //创建苹果电脑工厂
        IComputerFactory MyAppleFactory = new AppleComputerFactory();

        //生产苹果显示器
        IDisplay AppleDisplay = MyAppleFactory.ProduceADisplay();
        AppleDisplay.Show();		//苹果显示器正常工作!

        //创建戴尔电脑工厂
        IComputerFactory MyDellFactory = new DellComputerFactory();

        //生产戴尔主机
        IMainFrame DellMainFrame = MyDellFactory.ProduceAMainFrame();
        DellMainFrame.Open();		//戴尔主机启动成功!
    }
}

UML图

参考

posted @ 2019-12-01 22:11  SouthBegonia  阅读(392)  评论(0编辑  收藏  举报