抽象工厂模式 [英] Abstract factory pattern

查看:40
本文介绍了抽象工厂模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  1. C# 中抽象工厂模式的好例子?
  2. 抽象工厂模式在 C# 中的优点是什么?
  3. 如何在抽象工厂模式中使用 C# 泛型?
  4. 如何使用抽象工厂模式进行单元测试?

解决方案

首先,我建议你阅读抽象工厂模式,例如 此处.现在我将尝试解释为什么你会使用这种模式.

通常,如果您使用工厂模式,您将在工厂中创建对象.当您有一个给定类(或多个类)的多个实现时,就会出现问题.现在,这些多个实现被分组.当您有一个工厂时,您将使用 抽象工厂模式,但您希望按组对对象的创建进行分组.

好吧,上面的解释可能不是很清楚,所以我举个例子.

假设您有一个带有数据代理的类库.数据代理为您提供访问和存储不同数据的方法.当然,有多种存储数据的方式.例如:在数据库中、在 XML 文件中、在服务中、.对于这些可能的方式中的每一种,您都希望拥有数据代理.现在的问题是,您不希望有人将 DataAgentA 用于 XML 文件,并将 DataAgentB 用于数据库(假设我们有实体 A 和 B).用户应该只使用一个存储引擎.

让我向您介绍抽象工厂模式.

您将确保用户无法直接实例化您的数据代理,但他们必须将这些数据代理从工厂中取出.(一个额外的好处是,当您使用例如数据库 (EF) 时,您可以进行内部连接以确保您的数据代理使用相同的上下文等.)我们如何实现这一点?我们将数据代理的构造函数设置为内部".除此之外,我们为每个存储引擎创建不同的工厂.现在,由于这些工厂都做同样的事情,我们也有这些接口(就像我们的数据代理一样,因为它们都必须做同样的事情,对吧!?).

下面是我们的接口.基本上这是工厂模式,但只是现在我们谈论的是接口而不是.

公共接口IAgentA{//在这里添加一些方法!}公共接口 IAgentB{//在这里添加一些方法!}公共接口 IAgentFactory{IAgentA CreateAgentA();IAgentB CreateAgentB();}

现在对于这两个代理,我们有两种可能的实现方式,一种用于 XML,一种用于数据库存储(同样:这是一个示例,您可以拥有任意数量的实现类型).这些实现看起来像这样(见下文).请注意,我将构造函数设为 internal!这是此代码块之后的部分所必需的.

公共类 AgentA_Xml : IAgentA{内部 AgentA_Xml(){/* 在这里构造 */}//IAgentA 方法实现}公共类 AgentB_Xml : IAgentB{内部 AgentB_Xml(){/* 在这里构造 */}//IAgentB 方法实现}公共类 AgentA_Database : IAgentA{内部 AgentA_Database(){/* 在这里构造 */}//IAgentA 方法实现}公共类 AgentB_Database : IAgentB{内部 AgentB_Database(){/* 在这里构造 */}//IAgentB 方法实现}

现在因为构造函数是内部的.这会导致您无法在程序集之外实例化这些类,这通常是您对此类情况所做的.现在我们必须创建我们的工厂.

公共类 XMLAgentFactory : IAgentFactory{公共 IAgentA CreateAgentA(){返回新的 AgentA_Xml();}公共 IAgentB CreateAgentB(){返回新的 AgentB_Xml();}}公共类 DatabaseAgentFactory : IAgentFactory{公共 IAgentA CreateAgentA(){返回新的 AgentA_Database();}公共 IAgentB CreateAgentB(){返回新的 AgentB_Database();}}

由于两个工厂都实现了 IAgentFactory 接口,用户可以轻松地更改 AgentFactory 实现(如果他,在这种情况下,想要使用不同的存储引擎)而无需必须更改他编写的任何其他代码(针对代理),只要他针对接口进行编程(显然).

以上解释希望能回答您的问题(1)和(2).

<块引用>

  1. C# 中抽象工厂模式的好例子?
  2. 以及抽象工厂模式在 C# 中的优势是什么?

回答您的问题 (3).

<块引用>

  1. 如何在抽象工厂模式中使用 C# 泛型?

您仍然可以使用泛型,当您使用抽象工厂模式时,这不会改变任何一点.当然,您必须创建通用工厂方法(create 方法),但这应该没有任何问题.

回答您的问题 (4).

<块引用>

  1. 如何使用抽象工厂模式进行单元测试?

就像您对任何其他类进行单元测试一样.只有一件事会有所不同.

由于您可能还想测试您的类的构造函数(以及其他内部方法),您需要使内部构造函数(方法)对您的单元测试项目可见(并且您不想更改 <代码>内部到public).这可以通过将以下行添加到您的项目(工厂和类所在的项目)的 AssemblyInfo.cs 文件中来轻松完成:

[程序集:System.Runtime.CompilerServices.InternalsVisibleTo("My.UnitTest.Namespace")]

您可以在 <上找到有关 InternalsVisibleTo 属性的更多信息(和备注)强>MSDN.

我希望这能回答你的问题.

  1. Good example for Abstract factory pattern in C#?
  2. What are the advantages of the Abstract factory pattern in C#?
  3. How to use C# generics with the Abstract factory pattern?
  4. How to unit test with the Abstract factory pattern?

解决方案

First of all, I would suggest you to read about the Abstract Factory pattern, for example here. Now I will try to explain why you would use this pattern.

Normally, if you use the Factory pattern, you will create objects in a Factory. The problem arises when you have multiple implementation of a given class (or classes). Now, those multiple implementations are grouped. You will use the Abstract Factory pattern when you have a factory, but you would like to group the creating of objects per group.

Okay, above explanation might not be completely clear, so I will give you an example.

Let's say you have a class library with data agents. Data agents provide you methods to access and store different data. Of course, there are multiple ways of storing your data. For example: in a database, in XML file, over a service, . For each of these possible ways, you would like to have data agents. Now the problem is, you don't want that someone uses the DataAgentA for XML files together with DataAgentB for database (let's assume that we have entities A and B). The user should use only one storage engine.

Let me introduce you the Abstract Factory pattern.

You will make sure that users cannot directly instantiate your Data Agents, but they will have to get these data agents out of a factory. (An extra advantage is, that when you use for example a database (EF), you can do internal wiring to make sure your Data Agents use the same context, etc.) How do we accomplish this? We set the constructor of our data agents to ´internal´. Apart from that, we create different factories for each storage engine. Now, since those factories all do the same, we also have these interfaced (just like our data agents, since they all have to do the same, right!?).

Below we have our interfaces. Basically this is the factory pattern, but only now instead of about classes, we are talking about interfaces.

public interface IAgentA 
{
    // Add some methods here!
}

public interface IAgentB
{
    // Add some methods here!
}

public interface IAgentFactory
{
    IAgentA CreateAgentA();
    IAgentB CreateAgentB();
}

Now for the two agents, we have two possible implementations, one for XML and one for database storage (again: this is an example, you can have as many implementation types as you want). Those implementations would look like this (see below). Please note that I made the constructor internal! This is needed for the part that comes after this code block.

public class AgentA_Xml : IAgentA
{
    internal AgentA_Xml()
    { /* Construction here */}

    // IAgentA method implementations
}

public class AgentB_Xml : IAgentB
{
    internal AgentB_Xml()
    { /* Construction here */}

    // IAgentB method implementations
}


public class AgentA_Database : IAgentA
{
    internal AgentA_Database()
    { /* Construction here */}

    // IAgentA method implementations
}

public class AgentB_Database : IAgentB
{
    internal AgentB_Database()
    { /* Construction here */}

    // IAgentB method implementations
}

Now as the constructors are internal. This causes that you cannot instantiate those classes outside the assembly, which is generally what you do with these kind of cases. Now we have to create our factories.

public class XMLAgentFactory : IAgentFactory
{
    public IAgentA CreateAgentA()
    {
        return new AgentA_Xml();
    }

    public IAgentB CreateAgentB()
    {
        return new AgentB_Xml();
    }
}


public class DatabaseAgentFactory : IAgentFactory
{
    public IAgentA CreateAgentA()
    {
        return new AgentA_Database();
    }

    public IAgentB CreateAgentB()
    {
        return new AgentB_Database();
    }
}

Since both factories implement the IAgentFactory interface, the user can easily change of AgentFactory implementation (if he, in this case, wants to use a different storage engine) without having to change any other code he wrote (against the agents), as long as he programmed against the interfaces (obviously).

Above explanation hopefully answers your questions (1) and (2).

  1. Good example for Abstract factory pattern in C#?
  2. and what are advantages of Abstract factory pattern in c#?

Answering your question (3).

  1. How use C# generics with Abstract factory pattern?

You can still use generics, this doesn't change any bit when you use an Abstract Factory pattern. Of course, you will have to create generic factory methods (the create methods), but that shouldn't be any problem.

Answering your question (4).

  1. How does unit test with Abstract factory pattern?

Just the same as you would unit test any other class. Only one thing will be different.

Since you probably also want to test the constructor of your classes (and maybe other internal methods), you need to make the internal constructors (methods) visible to your unit test project (and you don't want to change the internal to public). This is easily done by adding the following line to your AssemblyInfo.cs file of your project (the project where your factory and classes are in):

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("My.UnitTest.Namespace")]

You can find more information (and remarks) about the InternalsVisibleTo attribute on MSDN.

I hope this kind of answers your question.

这篇关于抽象工厂模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆