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
四、理解不使用工厂设计模式的问题
上述代码实现引入了以下问题
- 首先,客户端类(程序)和产品类(MoneyBack、Titanium 和 Platinum)之间的**紧密耦合。**因此,当对一个类进行更改时,也必须对其他类进行更改。
- 其次,假设添加一张新的信用卡。那么,还需要修改客户端代码,即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())会更简单、更直接。
- 性能关键情况:在性能关键的实时应用程序中,工厂模式中额外的抽象层和方法调用的开销可能是不可取的。在这种情况下,直接实例化对象可能会更有效。
- 有限的对象变化:如果您的应用程序只需要对象的一些固定实例或类型,并且这些实例或类型在将来不太可能更改或扩展,则工厂模式提供的灵活性可能是不必要的。
- 增加复杂性:有时,引入工厂可能会使代码比需要的更复杂,特别是在范围较小或对象创建过程不太可能改变的应用程序中。这种增加的复杂性会使代码更难理解和维护。
- 依赖注入框架:使用依赖注入框架可能已经提供了对象创建和生命周期管理所需的功能。在这种情况下,添加工厂模式可能会导致冗余代码。
- 测试和调试挑战:使用工厂有时会使测试和调试变得更加复杂,因为它增加了一个额外的跟踪层。在简单性是有效测试和维护的关键的场景中,避免工厂模式可能是有益的。