C#设计模式——工厂模式

C#设计模式——工厂模式

​ 工厂设计模式是实时应用程序中最常用的设计模式之一。工厂设计模式属于创意设计模式类别。这里主要介绍以下相关内容:

​ 一、什么是工厂设计模式

​ 二、通过示例了解工厂设计模式

​ 三、在 C# 中不使用工厂模式的示例

​ 四、理解不使用工厂设计模式的问题

​ 五、工厂设计模式在C# 中的实现

​ 六、理解工厂设计模式的UML图

​ 七、何时在实时应用中使用工厂设计模式

​ 八、何时不在实时应用程序中使用工厂设计模式

一、什么是工厂设计模式

​ 工厂是一个用于创建其他对象的对象。用技术术语来说,我们可以说工厂是一个带有方法的类。该方法将根据接收到的输入参数“创建并返回不同的对象,简单来说,如果我们有一个超类和 n 个子类,并且根据提供的数据,如果我们必须创建并返回其中一个子类的对象,那么我们需要使用 C# 中的工厂设计模式。在工厂设计模式中,我们创建一个对象,而不将对象创建和初始化逻辑暴露给客户端,客户端将使用公共接口引用新创建的对象。工厂设计模式背后的基本原理是,在运行时,我们根据传递的参数获取相似类型的对象。因此,客户端将获取适当的对象并使用该对象,而无需知道该对象是如何创建和初始化的。

二、通过实例了解工厂设计模式

​ 现有三种信用卡类别,即MoneyBack, Titanium, and Platinum。这三个类是 CreditCard 超类的子类,或者可以说是超级接口。CreditCard接口具有三个方法,即GetCardType、GetCreditLimit和GetAnnualCharge。MoneyBack、Titanium、Platinum 子类都实现了CreditCard 的上述三个方法。

在这里插入图片描述

我们需要要求用户选择信用卡。用户选择信用卡后,我们需要显示有关所选信用卡的所需信息。让我们首先讨论在 C# 中不使用工厂设计模式来实现这一点。然后,我们将讨论这些问题,最后,我们将使用 C# 中的工厂设计模式创建相同的应用程序。

三、在 C# 中不使用工厂模式的示例

步骤 1:创建抽象产品或产品接口(信用卡)

​ 我们需要创建一个接口或一个抽象类来公开信用卡应具有的操作。因此,创建一个名为CreditCard.cs的类文件并复制并粘贴以下代码。正如您所看到的,我们根据我们的要求使用三种方法创建了 CreditCard 接口。

namespace FactoryDesignPattern
{
    public interface CreditCard
    {
        string GetCardType();
        int GetCreditLimit();
        int GetAnnualCharge();
    }
}

接下来创建三个Product类来实现上述接口。

步骤2:创建产品类(MoneyBack, Titanium, and Platinum

​ 示例中,有三张信用卡。因此,需要通过实现 CreditCard 接口并为所有三个 CreditCard 方法提供实现来创建三个类。首先,创建一个名为MoneyBack.cs 的类文件。

namespace FactoryDesignPattern
{
    class MoneyBack : CreditCard
    {
        public string GetCardType()
        {
            return "MoneyBack";
        }

        public int GetCreditLimit()
        {
            return 15000;
        }

        public int GetAnnualCharge()
        {
            return 500;
        }
    }
}

此类实现了 CreditCard 接口并提供了所有三个方法的实现。同样,再对其他两种信用卡类别执行相同的操作。

Titanium.cs:

namespace FactoryDesignPattern
{
    public class Titanium : CreditCard
    {
        public string GetCardType()
        {
            return "Titanium Edge";
        }
        public int GetCreditLimit()
        {
            return 25000;
        }
        public int GetAnnualCharge()
        {
            return 1500;
        }
    }
}

Platinum.cs:

namespace FactoryDesignPattern
{
    public class Platinum : CreditCard
    {
        public string GetCardType()
        {
            return "Platinum Plus";
        }
        public int GetCreditLimit()
        {
            return 35000;
        }
        public int GetAnnualCharge()
        {
            return 2000;
        }
    }
}
步骤3:客户端代码(主要方法)

​ 客户端代码只不过是需要使用产品类(MoneyBack、Titanium 和 Platinum)的类。在示例中,它将是 Program 类的 Main 方法。我们将要求用户在客户端代码中选择信用卡类型。基于选定的信用卡,创建上述三个产品实现类(MoneyBack、Titanium 和 Platinum)中任意一个的实例,并调用方法来显示信用卡详细信息。因此,修改 Program 类的 Main 方法如下。

using System;
namespace FactoryDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {          
            string cardType = "MoneyBack";

            CreditCard cardDetails = null;

            if (cardType == "MoneyBack")
            {
                cardDetails = new MoneyBack();
            }
            else if (cardType == "Titanium")
            {
                cardDetails = new Titanium();
            }
            else if (cardType == "Platinum")
            {
                cardDetails = new Platinum();
            }

            if (cardDetails != null)
            {
                Console.WriteLine("CardType : " + cardDetails.GetCardType());
                Console.WriteLine("CreditLimit : " + cardDetails.GetCreditLimit());
                Console.WriteLine("AnnualCharge :" + cardDetails.GetAnnualCharge());
            }
            else
            {
                Console.Write("Invalid Card Type");
            }

            Console.ReadLine();
        }
    }
}

上面的代码实现非常简单。获得 CardType 值后,使用 IF-ELSE 条件创建适当的信用卡实例。然后调用这三个方法在控制台窗口上显示信用卡信息。因此,运行该应用程序时,获得预期的输出,如下所示。

CardType :MoneyBack
CreditLimit :1500
AnnualCharge :500

四、理解不使用工厂设计模式的问题

上述代码实现引入了以下问题

  1. 首先,客户端类(程序)和产品类(MoneyBack、Titanium 和 Platinum)之间的**紧密耦合。**因此,当对一个类进行更改时,也必须对其他类进行更改。
  2. 其次,假设添加一张新的信用卡。那么,还需要修改客户端代码,即Program类的main方法,增加一个额外的**IF-ELSE条件,**这不仅增加了开发的开销,而且增加了测试过程的开销。

接下来将实现如何使用 C# 中的工厂设计模式来克服上述问题。

五、工厂设计模式在C# 中的实现

​ 根据工厂设计模式的定义,工厂设计模式创建一个对象,而不将对象创建逻辑暴露给客户端,客户端使用公共接口引用新创建的对象。

​ 如下面的图片所示,工厂类负责创建并返回适当的产品(即 MoneyBack、Titanium 和 Platinum)对象。该类有一个静态方法,即 GetCreditcard,并且该方法采用一个输入参数,并且根据参数值,它将创建信用卡(即 MoneyBack、Platinum 和 Titanium)对象之一,并且将该对象存储在超类(CrditCard)引用变量中,最后将该超类引用变量返回给该方法的调用者,即客户端。
在这里插入图片描述

​ 现在,客户端只需要通过CreditCardFactory即可获取该对象。例:

 CreditCard cardDetails = CreditCardFactory.GetCreditCard("Platinum");
 cardDetails.GetCardType();
 cardDetails.GetCreditLimit();
 cardDetails.GetAnnualCharge();
步骤四:创建工厂类

​ 创建一个名为CreditCardfactory.cs的类文件,此类包含创建和初始化适当对象并根据某些条件返回该对象的逻辑。该类包含一个静态方法,该静态方法采用一个字符串参数,并根据参数值创建并向客户端返回适当的产品实例(MoneyBack、Titanium 和 Platinum)。

namespace FactoryDesignPattern
{
    public class CreditCardFactory
    {
        public static CreditCard GetCreditCard(string cardType)
        {
            CreditCard cardDetails = null;

            if (cardType == "MoneyBack")
            {
                cardDetails = new MoneyBack();
            }
            else if (cardType == "Titanium")
            {
                cardDetails = new Titanium();
            }
            else if (cardType == "Platinum")
            {
                cardDetails = new Platinum();
            }

            return cardDetails;
        }
    }
}
步骤5:在客户端代码中使用工厂类获取产品实例
using System;
namespace FactoryDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            CreditCard cardDetails = CreditCardFactory.GetCreditCard("Platinum");
            
            if (cardDetails != null)
            {
                Console.WriteLine("CardType : " + cardDetails.GetCardType());
                Console.WriteLine("CreditLimit : " + cardDetails.GetCreditLimit());
                Console.WriteLine("AnnualCharge :" + cardDetails.GetAnnualCharge());
            }
            else
            {
                Console.Write("Invalid Card Type");
            }

            Console.ReadLine();
        }
    }
}

输出:

CardType :Platinum Plus
CreditLimit : 35000
AnnualCharge :2000

六、工厂设计模式UML(类)图

在这里插入图片描述

以下是工厂设计模式 UML 图中典型组件的细分:

  • 产品接口/抽象产品:这表示定义具体产品必须实现的方法的接口或抽象类。在示例中,是信用卡接口。
  • 具体产品:这些是实现 Product 接口或扩展抽象类的类。它们是工厂将创建的实际对象。在示例中,是 MoneyBack、Platinum 和 Titanium 类别。
  • Creator 或 Factory:此类提供工厂方法来返回特定具体产品的实例。在示例中,是 CreditCardFactory 类。
  • 客户端:将使用实际产品对象的类。在示例中,是 Program 类的 Main 方法。

七、何时在 C# 实时应用程序中使用工厂设计模式

以下是实时应用程序中的一些场景,您可以考虑在 C# 中使用工厂设计模式:

  • 复杂对象创建:当对象的创建逻辑很复杂并且不应该是客户端代码的一部分时。工厂模式抽象了实例化过程并向客户端隐藏了复杂性。
  • 解耦:当类的实现与其用户之间需要解耦时,它很有用。工厂模式通过让类将实例化推迟到子类或另一个类来实现这一点。
  • 有条件的对象创建:如果对象的创建取决于某些条件或配置,工厂模式可以封装这些条件并确保创建适当的对象。
  • 可扩展性:当系统需要可扩展时,允许轻松添加符合接口或抽象类的新类型的对象,而无需修改现有代码。
  • 对象池:在对象创建成本高昂的场景中,您需要有效地管理和重用实例,例如在数据库连接或线程池中。
  • 对象族:如果您的应用程序需要创建一系列相关或依赖的对象,工厂模式可以确保创建的对象彼此兼容。
  • 集成和单元测试:为了更轻松地集成和单元测试,工厂模式允许创建模拟对象和存根,可以比直接实例化更有效地用于单元测试。
  • 可读性和可维护性:它通过将创建逻辑封装在一个地方并促进关注点的清晰分离来提高代码的可读性和可维护性。

八、何时不在 C# 实时应用程序中使用工厂设计模式?

  • 简单的对象创建:如果可以直接创建对象而不需要复杂的逻辑或依赖关系,那么使用工厂可能有点过头了。例如,如果您的类很简单并且不需要任何初始化参数,则直接实例化(new ClassName())会更简单、更直接。
  • 性能关键情况:在性能关键的实时应用程序中,工厂模式中额外的抽象层和方法调用的开销可能是不可取的。在这种情况下,直接实例化对象可能会更有效。
  • 有限的对象变化:如果您的应用程序只需要对象的一些固定实例或类型,并且这些实例或类型在将来不太可能更改或扩展,则工厂模式提供的灵活性可能是不必要的。
  • 增加复杂性:有时,引入工厂可能会使代码比需要的更复杂,特别是在范围较小或对象创建过程不太可能改变的应用程序中。这种增加的复杂性会使代码更难理解和维护。
  • 依赖注入框架:使用依赖注入框架可能已经提供了对象创建和生命周期管理所需的功能。在这种情况下,添加工厂模式可能会导致冗余代码。
  • 测试和调试挑战:使用工厂有时会使测试和调试变得更加复杂,因为它增加了一个额外的跟踪层。在简单性是有效测试和维护的关键的场景中,避免工厂模式可能是有益的。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
原型模式是一种创建型设计模式,其提供了一种复制已有对象的方法来生成新对象的能力,而不必通过实例化的方式来创建对象。原型模式是通过克隆(浅复制或深复制)已有对象来创建新对象的,从而可以避免对象创建时的复杂过程。 在C#中,可以通过实现ICloneable接口来实现原型模式。ICloneable接口定义了Clone方法,该方法用于复制当前对象并返回一个新对象。需要注意的是,Clone方法返回的是Object类型,需要进行强制类型转换才能得到复制后的对象。 以下是一个简单的示例代码: ```csharp public class Person : ICloneable { public string Name { get; set; } public int Age { get; set; } public object Clone() { return MemberwiseClone(); } } // 使用示例 var person1 = new Person { Name = "Tom", Age = 20 }; var person2 = (Person)person1.Clone(); person2.Name = "Jerry"; Console.WriteLine(person1.Name); // 输出 "Tom" Console.WriteLine(person2.Name); // 输出 "Jerry" ``` 在上面的示例代码中,实现了一个Person类,并实现了ICloneable接口中的Clone方法来实现原型模式。复制对象时,使用MemberwiseClone方法进行浅复制,即只复制值类型的字段和引用类型字段的引用,而不复制引用类型字段所引用的对象。在使用示例中,首先创建一个Person对象person1,然后通过Clone方法复制一个新的对象person2,修改person2的Name属性后,输出person1和person2的Name属性,可以看到person1的Name属性并没有改变,说明person2是一个全新的对象。 需要注意的是,如果要实现深复制,即复制引用类型字段所引用的对象,需要在Clone方法中手动将引用类型字段复制一份。另外,使用原型模式时,需要注意复制后的对象和原对象之间的关系,如果复制后的对象修改了原对象的状态,可能会对系统产生意想不到的影响。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值