使用接口 - 设计模式方面

4
我正在寻找一篇简短的文章和示例,讲述如何使用接口。我对技术部分不感兴趣,但需要了解设计方面的内容。例如,如何使用接口进行编程,何时以及如何创建实现,以及在常规开发中使用接口的设计模式。
我有很多相似的类以几种不同的方式重复出现。我想使用接口和抽象类使事情更加模块化 - 但我无法找到正确的方法。
4个回答

14

接口定义了一个契约,它承诺对象将以特定的方式运行。在学习接口之前,你往往会用具体的术语想象对象。例如,假设我们有一列产品:

List<string> products = new List<string>() { "desktop", "laptop", "server" };

我们有一个打印出产品信息的方法:

void PrintProducts(List<string> products)
{
     foreach (string product in products)
     { 
          Console.WriteLine(product);
     }
}
我们的方法与List的具体类型相关联。但是这样做必要吗?在C#中有很多不同类型的集合:List、Array、ReadOnlyCollection等等。你所需要做的就是遍历它们,其中列表(List)有很多数组没有的方法,但你在这里并没有使用到它们。幸运的是,它们都实现了IEnumerable接口。这意味着它们都“契约性地绑定”能够被枚举。
像下面这样修改方法:
void PrintProducts(IEnumerable<string> products)
{
     foreach (string product in products)
     { 
          Console.WriteLine(product);
     }
}

这意味着你现在可以传递一个数组,或者列表,或者你自己创建的某些独特容器。

另一个例子:假设你有一个数据存储库:

public class DatabaseRepository
{
    public void AddProduct(Product product)
    {
        // connect to the database
        // add the product
    }
}

你有一些需要使用这个数据库的类:

public class ProductManager
{
    DatabaseRepository _repository;

    public ProductManager(DatabaseRepository repository)
    {
         _repository= repository;
    }
}

不幸的是,这个类与您的数据库相关联。如果您决定更改为存储为XML文件或在云键值存储中进行存储,则必须更改您的ProductManager,这很难且容易出错。相反,假设我们定义了一个接口:

public interface IRepository {
    void AddProduct(Product product);
}

将我们的ProductManager类更改为使用此接口:

public class ProductManager
{
    IRepository _repository;

    public ProductManager(IRepository repository)
    {
         _repository= repository;
    }
}

这意味着无论存储库的类型是什么,我们都知道始终会有一个名为AddProduct(Product product)的方法。现在我们可以创建XML存储库:

public class XMLRepository : IRepository 
{
    public void AddProduct(Product product)
    {
         // write to an XML file
    }
}

现在,我们可以自由地传入任何仓库:

ProductManager manager = new ProductManager(new DatabaseRepository())
或者
ProductManager manager = new ProductManager(new XMLRepository())

我们的ProductManager也是完全相同的行为。它对具体类型毫不知情。

当进行单元测试时,这变得非常有用。当您对接口的工作原理有坚实的理解后,反转控制是您想要深入了解的内容。


谢谢,这真的很有帮助,我明白了。我只是在寻找如何在实际大型项目中使用接口的示例。一些通用的设计模式或指南,以便在创建对象时使用接口或不使用接口等。 - Naor
接口真的没有“设计模式”。接口是语言的构造,使事情更加灵活。您可以假定在不使用接口的情况下使用所有设计模式。然而,ProductManager类的最后一个示例是为什么您希望在大型产品上使用它的原因之一。它使得每个子系统保持松散耦合。我最近切换到使用Azure存储而不是文件系统存储。这很简单,因为有了门面和接口,我不需要更改一堆类。 - mfanto
我理解你的意思,但是我仍然需要一种使用这些接口的“方法”。为每个类创建接口似乎并不合理 - 对吗?那么我应该在什么时候以及如何使用它们呢? - Naor
我知道你在答案中想要什么,呵呵,但我现在不确定如何以一种有意义的方式回答它 :). 我有一个更好的想法。给我一个你应用程序中的例子。你的数据库层,电子邮件层等。我可以解释一下如何使用接口,而不是谈论抽象概念和简单的例子。但是,是的,你可能确实有很多接口。接口对于单元测试至关重要,因此我的几乎所有类都有自己的接口。 - mfanto

2
这本书是设计模式的权威参考书,包含使用接口的示例。但是你可能想要从更基础的层面开始学习。《Java编程思想》是我进入面向对象编程的起点,对于C#也有类似的书籍,尽管书中内容应该大多数与语言无关。你还可以搜索关于面向对象编程的在线教程。
编辑:关于模式及其在C#中的实现和使用,一本很好的书是《C# 3.0设计模式》。

@gof书不适合那些询问接口是什么的人阅读。 - dantuch
@dantuch,几乎没有模式只是关于接口的。大多数模式基本上使用接口。所以这种分离对我来说看起来毫无意义。 - Andrey

1

何时使用接口 接口允许某人从头开始实现您的接口或在一些其他代码中实现您的接口,其原始或主要目的与您的接口完全不同。对于他们来说,您的接口只是附带的东西,必须添加到他们的代码中才能使用您的包。缺点是接口中的每个方法都必须是公共的。您可能不想暴露所有内容。

何时使用抽象类 相比之下,抽象类提供了更多的结构。它通常定义了一些默认实现并提供了一些有用的工具,可用于完整的实现。问题在于,使用它的代码必须将您的类作为基础。如果其他想要使用您的包的程序员已经独立开发了自己的类层次结构,那么这可能非常不方便。在Java中,一个类只能继承自一个基类。

或阅读此文: http://mindprod.com/jgloss/interfacevsabstract.html


1
@Naor,根据您上面的评论“为每个类创建接口似乎不合逻辑 - 对吗?”,我认为最适合您阅读的书籍是《Head First设计模式》 - 它有一种令人难以置信且易于理解的教学方式,可以教您如何使用和应用设计模式。我第一次在这本书中读到它们,并且它确实改变了我的想法!通过阅读此书,您将能够阅读更复杂的内容,例如Martin Fowler,《企业应用架构模式》 - 我相信它正好涉及您想要的模式的实际应用。直接阅读GoF、M. Fowler或更复杂的内容可能会让您失望或浪费时间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接