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

1 回答 1

142

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

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

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

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

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

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

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

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

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

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

现在对于这两个代理,我们有两种可能的实现,一种用于 XML,另一种用于数据库存储(再次说明:这是一个示例,您可以拥有任意数量的实现类型)。这些实现看起来像这样(见下文)。请注意,我制作了构造函数internal!这是该代码块之后的部分所必需的。

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
}

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

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();
    }
}

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

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

  1. C# 中抽象工厂模式的好例子?
  2. c# 中抽象工厂模式的优点是什么?

回答你的问题(3)。

  1. 如何将 C# 泛型与抽象工厂模式结合使用?

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

回答你的问题(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.

于 2012-05-09T09:47:15.183 回答