C# 创建型设计模式----工厂模式

1 、什么是工厂模式

简单来说就是由一个对象去生成不同的对象,工厂模式是用工厂方法代替new操作的一种模式。工厂方法封装了多个相关联类的new方法,每次实例化这些类的时候不需要new多次,只需要调用工厂类的对应方法即可实例化这些类,并且是通过使用一个共同的接口来指向新创建的对象。

工厂模式主要有三种类型:简单工厂(不介绍)工厂方法抽象工厂

2、工厂模式的作用

在创建对象时必然需要new该对象,当需要更改对象时,需要把项目中所有地方都修改一遍,这显然违背了软件设计的开闭原则。如果使用工厂来生成对象,那么我们只需要跟工厂打交道就可以了。如果要更新对象时,直接在工厂里更换即可。这就实现了对象解耦。

所以工厂模式主要用来解耦代码,将对象的创建和使用分离,使得代码更加灵活和可维护。

3、工厂方法

3.1、工厂方法模式的主要角色:

抽象工厂 :在抽象工厂类中声明了工厂方法,用于返回一个产品。提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。

具体工厂:它是抽象工厂类的子类,实现了在抽象工厂中声明的工厂方法,完成具体产品的创建。并可由客户端调用,返回一个具体产品类的实例。

抽象产品 :它是定义产品的接口,定义了产品的规范,描述了产品的主要特性和功能,是工厂方法模式所创建对象的公共父类

具体产品:它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间相互对应。

3.2、创建工厂方法

抽象工厂:提供基类,通俗理解就是。有这么一个专门生产电蒸锅的集团架构(别问为什么是电蒸锅,因为我现在想买)。集团不提供锅,只提供流水线的基建,和产品的基本概念。

 /// <summary>
 ///抽象工厂--电蒸锅集团,专门生产各种电蒸锅
 /// </summary>
 public abstract class ElectricFactory
 {
     /// <summary>
     /// 声明获取抽象产品类方法(具体实现在其子类)--提供生产电蒸锅的流水线,流水线具体怎么生产,生产哪种集团不管
     /// </summary>
     /// <returns></returns>
     public abstract Electric GetElectric();
 }

具体工厂:继承抽象工厂--也就是具体的生产厂家,都是继承集团的流水线并定义里面具体的生产方式

/// <summary>
/// 具体工厂-美的流水线
/// </summary>
public class MDElectricFactory : ElectricFactory//美的属于该集团下的工厂
{
    /// <summary>
    /// 实现抽象方法,具体操作在里面
    /// </summary>
    /// <returns></returns>
    public override Electric GetElectric()//美的使用集团提供的流水线,集团提供什么,美的就能使用什么
    {
        Console.WriteLine("美的生产了一个锅");
        return new MDElectric();//返回具体产品-美的电蒸锅
    }
}
/// <summary>
/// 具体工厂-苏泊尔流水线
/// </summary>
public class SBRElectricFactory : ElectricFactory//苏泊尔属于该集团下的工厂
{
    /// <summary>
    /// 实现抽象方法,具体操作在里面
    /// </summary>
    /// <returns></returns>
    public override Electric GetElectric()//使用集团提供的流水线
    {
        Console.WriteLine("苏泊尔生产了一个锅");
        return new SBRElectric();//返回具体产品-苏泊尔电蒸锅
    }
}

抽象产品:集团告诉你这是电蒸锅,它有什么功能,下面的工厂生产的产品得有这个功能,至于功能怎么实现的集团不管。

/// <summary>
/// 抽象产品电蒸锅---集团定义的电蒸锅整个品类
/// </summary>
public abstract class Electric
{
    /// <summary>
    /// 抽象方法-定义电蒸锅有蒸东西的基本功能,具体怎么蒸就是下面的厂家决定。
    /// </summary>
    public abstract void Fun();

    /// <summary>
    /// 抽象产品提供拓展方法--子类产品非必须使用的,但可以有,就像有些电蒸锅有预约功能,有些没有。
    /// 而且最好是具体产品的共有的特性(公共方法),不建议是小众特性(仅适用于某个具体产品的方法),
    /// 例如电蒸锅的预约功能就很大众,可以有,
    /// 如果某个厂家要加一个烤盘功能,这就属于小众,放在具体厂家那里去实现更合适。
    /// </summary>
    public void AddFunction(string name)
    {
        Console.WriteLine($"{name}加了一个预约功能");
    }
}

具体产品:电蒸锅的蒸东西的功能具体实现方式

  /// <summary>
  /// 具体产品-美的电蒸锅
  /// </summary>
  public class MDElectric : Electric//这是美的电蒸锅,必须包含集团定义的电蒸锅的必备功能的同时也可以自己拓展
  {
      /// <summary>
      /// 具体的实现方法
      /// </summary>
      public override void Fun()
      {
          Console.WriteLine("美的电蒸锅蒸东西的功能是用大火蒸东西");
      }
  }
  /// <summary>
  /// 具体产品-苏泊尔电蒸锅
  /// </summary>
  public class SBRElectric : Electric//这是苏泊尔电蒸锅
  {
      public override void Fun()
      {
          Console.WriteLine("苏泊尔电蒸锅蒸东西的功能是用中火蒸东西");
      }
  }

使用:

private void WTBtn_Click(object sender, EventArgs e)
{
    ElectricFactory electric;//创建了一个电蒸锅集团。

    electric = new MDElectricFactory();//美的接入集团
    var DZG = electric.GetElectric();//美的使用集团生产线,定义生产线的具体流程并生产一个锅
    DZG.Fun();//这个锅实现具体的功能


    electric = new SBRElectricFactory();//苏泊尔接入集团
    var DZG1 = electric.GetElectric();//苏泊尔使用集团生产线,定义生产线的具体流程并生产一个锅
    DZG1.Fun();//这个锅实现具体的功能
    DZG1.AddFunction("苏泊尔");//看到电蒸锅大类(抽象产品)里可以加一个功能,让苏泊尔给这个锅加一个。
}

运行结果:

通过调用方式可以看出,不同产品的生产由原来的总工厂变为了各个分工厂去负责。

用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。

在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则。

这就是一整个工厂方法。当然这样看下来估计也是懵懂的不知道它有什么作用。

我再用文字尝试说明一下:

来设想你现在需要开发一个电商平台的订单模块,其中需要生成不同类型的订单,比如普通订单、促销订单、团购订单等。每个订单里面有很多的参数。

按照常规的方式,我们直接创建每个订单类,然后全部new出来即可, 这样就没必要创建什么工厂类了对吧?

假设订单类名是OrderA、OrderB、OrderC。有很多参数的情况下New就得

OrderA A=new OrderA(参数1,参数2,.....);

要使用里面具体方法还得

A.方法1();A.方法2();........

但是现在你有各种各样的订单,这些订单是你不同的同事去开发的。如果按你上面的做法,首先你需要知道每一个订单类的情况,你需要知道要成功new出一个具体的订单类需要哪些参数、需要执行哪些方法。但是这明显是不现实的,你没有时间去看源码,甚至看不到源码。

因为你的工作只是new出订单类并调用里面的方法罢了,而每个订单类具体怎么写,其实你不需要知道,这个时候每个订单类对应一个具体的工厂类,你只需要调用工厂里的创建产品方法就行了。

再者从单依职责原则,解耦合来考虑。如果按常规new OrderA的写法,你的同事某个订单类修改了,势必会导致你写的程序会直接创建报错,你就得跟着修改。但是使用了工厂方法,根本不会影响你,因为你不参与创建实例,你的程序也不需要任何的改动。你的同事如何修改订单类跟你也没关系。

嗯.....这样说不知道有没有说明白它的作用。。。

4、抽象工厂

上面工厂模式不管工厂怎么拆分抽象,都只是针对一类产品,直接生成实例,这些工厂只生产同种类产品。

但是抽象工厂模式不同,抽象工厂模式并不直接生成实例, 而是用于对产品类簇的创建。

通俗点来讲就是:简单工厂和工厂方法模式的工作是生产产品,那么抽象工厂模式的工作就是生产工厂的。

是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

抽象工厂的最大好处在于交换产品系列非常方便,只需要改变具体工厂即可使用不同的产品配置。

总的来说工厂方法模式一个工厂只生产一个产品,抽象工厂模式一个工厂生产多个产品,形成一个产品套餐,而多个工厂组成套餐系列。

4.1、抽象工厂模式的主要角色:

**抽象工厂:**在抽象工厂类中声明了多个工厂方法,用于返回多个产品。提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。

**具体产品工厂:**它是抽象工厂类的子类,实现了在抽象工厂中声明的多个工厂方法,完成多个具体产品的创建。

**抽象产品:**它是定义一个产品的接口,定义了一个产品的规范,描述了一个产品的主要特性和功能。抽象工厂模式有多个抽象产品。

**具体产品:**实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

4.2 创建方式

抽象工厂:有多少个系列就可以创建多少个抽象工厂类。本实例只创建了一个电器系列的工厂。里面可以有许多同系列的电器产品。

/// <summary>
///抽象工厂--电器集团,专门生产各种电器
/// </summary>
public abstract class ElectricFactory
{
    /// <summary>
    /// 生产电蒸锅
    /// </summary>
    /// <returns></returns>
    public abstract Electric GetElectric();
    /// <summary>
    /// 生产电饭煲
    /// </summary>
    /// <returns></returns>
    public abstract Rice GetRice();
}

具体工厂:同一系列可以创建多个具体的工厂,负责同一系列下的不同产品出的创建。本示例是电器下的电蒸锅和电饭煲,当然还可以电视机,烧水壶啥的。

 /// <summary>
 /// 具体工厂-美的工厂
 /// </summary>
 public class MDFactory : ElectricFactory//美的属于该集团下的工厂
 {
     public override Electric GetElectric()
     {
         Console.WriteLine("美的生产了一个电蒸锅");
         return new MDElectric();//返回具体产品-美的电蒸锅
     }

     public override Rice GetRice()
     {
         Console.WriteLine("美的生产了一个电饭煲");
         return new MDRice();
     }
 }
 /// <summary>
 /// 具体工厂-苏泊尔工厂
 /// </summary>
 public class SBRFactory : ElectricFactory//苏泊尔属于该集团下的工厂
 {
     /// <summary>
     /// 实现抽象方法,具体操作在里面
     /// </summary>
     /// <returns></returns>
     public override Electric GetElectric()//使用集团提供的流水线
     {
         Console.WriteLine("苏泊尔生产了一个电蒸锅");
         return new SBRElectric();//返回具体产品-苏泊尔电蒸锅
     }

     public override Rice GetRice()
     {
         Console.WriteLine("苏泊尔生产了一个电饭煲");
         return new SBRRice();
     }
 }

抽象产品:有多少个不同产品就创建多少个抽象产品类。

 /// <summary>
 /// 抽象产品电蒸锅---集团定义的电蒸锅整个品类
 /// </summary>
 public abstract class Electric
 {
     /// <summary>
     /// 抽象方法-定义电蒸锅有蒸东西的基本功能,具体怎么蒸就是下面的厂家决定。
     /// </summary>
     public abstract void Fun();

     /// <summary>
     /// 抽象产品提供拓展方法--子类产品非必须使用的,但可以有,就像有些电蒸锅有预约功能,有些没有。
     /// 而且最好是具体产品的共有的特性(公共方法),不建议是小众特性(仅适用于某个具体产品的方法),
     /// 例如电蒸锅的预约功能就很大众,可以有,
     /// 如果某个厂家要加一个烤盘功能,这就属于小众,放在具体厂家那里去实现更合适。
     /// </summary>
     public void AddFunction(string name)
     {
         Console.WriteLine($"{name}加了一个预约功能");
     }
 }

 /// <summary>
 /// 抽象产品-电饭煲
 /// </summary>
 public abstract class Rice
 {
     public abstract void Fun();
 }

具体产品:不同产品继承不同抽象类。

 /// <summary>
 /// 具体产品-美的电蒸锅
 /// </summary>
 public class MDElectric : Electric//这是美的电蒸锅,必须包含集团定义的电蒸锅的必备功能的同时也可以自己拓展
 {
     /// <summary>
     /// 具体的实现方法
     /// </summary>
     public override void Fun()
     {
         Console.WriteLine("美的电蒸锅蒸东西的功能是用大火蒸东西");
     }
 }
 /// <summary>
 /// 具体产品-苏泊尔电蒸锅
 /// </summary>
 public class SBRElectric : Electric//这是苏泊尔电蒸锅
 {
     public override void Fun()
     {
         Console.WriteLine("苏泊尔电蒸锅蒸东西的功能是用中火蒸东西");
     }
 }

 /// <summary>
 /// 具体产品-美的电饭煲
 /// </summary>
 public class MDRice : Rice//这是美的电饭煲
 {
     /// <summary>
     /// 具体的实现方法
     /// </summary>
     public override void Fun()
     {
         Console.WriteLine("美的电饭煲蒸东西的功能是用大火蒸东西");
     }
 }
 /// <summary>
 /// 具体产品-苏泊尔电饭煲
 /// </summary>
 public class SBRRice : Rice//这是苏泊尔电饭煲
 {
     public override void Fun()
     {
         Console.WriteLine("苏泊尔电饭煲蒸东西的功能是用中火蒸东西");
     }
 }

调用:

  private void WTBtn_Click(object sender, EventArgs e)
  {
      ElectricFactory electric;//创建了一个电器集团。

      electric = new MDFactory();//美的工厂
      var DZG = electric.GetElectric();//生产一个电蒸锅锅
      DZG.Fun();//这个锅实现具体的功能
      var DFB = electric.GetRice();//生产一个电饭煲
      DFB.Fun();


      //换个工厂
      electric = new SBRFactory();//苏泊尔工厂
      var DZG1 = electric.GetElectric();//生产一个电蒸锅锅
      DZG1.Fun();//这个锅实现具体的功能
      DZG1.AddFunction("苏泊尔");//看到电蒸锅大类(抽象产品)里可以加一个功能,让苏泊尔给这个锅加一个。
      var DFB1 = electric.GetRice();//生产一个电饭煲
      DFB1.Fun();

  }

上面实例可以看出创建一个工厂可以产出不同的产品。

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

缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

END........................................................................

相关推荐
尘佑不尘19 分钟前
shodan5,参数使用,批量查找Mongodb未授权登录,jenkins批量挖掘
数据库·笔记·mongodb·web安全·jenkins·1024程序员节
SeniorMao0071 小时前
结合Intel RealSense深度相机和OpenCV来实现语义SLAM系统
1024程序员节
网安_秋刀鱼1 小时前
CSRF防范及绕过
前端·安全·web安全·网络安全·csrf·1024程序员节
WW、forever1 小时前
【ArcGIS Pro实操第4期】绘制三维地图
1024程序员节
记录学习-python1 小时前
Django-cookie,session
1024程序员节
b21431241 小时前
【运动的&足球】足球运动员球守门员裁判检测系统源码&数据集全套:改进yolo11-DBBNCSPELAN
1024程序员节
聪明的墨菲特i2 小时前
Vue组件学习 | 二、Vuex组件
前端·vue.js·学习·前端框架·1024程序员节
长潇若雪2 小时前
结构体(C 语言)
c语言·开发语言·经验分享·1024程序员节
DARLING Zero two♡3 小时前
关于我、重生到500年前凭借C语言改变世界科技vlog.12——深入理解指针(2)
c语言·开发语言·科技·1024程序员节
独行soc3 小时前
#渗透测试#SRC漏洞挖掘# 信息收集-Shodan进阶之Jenkins组件
安全·jenkins·安全威胁分析·1024程序员节·shodan