简体   繁体   English

编程到接口而不是实现混乱

[英]Program to an interface not an implementation confusion

I'm trying to get into the habit of coding to an interface rather than an implementation and whilst in most cases I can see the reasoning there are a few where I struggle. 我正在尝试养成对接口而不是对实现进行编码的习惯,尽管在大多数情况下,我可以看到推理的原因,但仍有一些困难。

Take this really simple example: 举一个非常简单的例子:

public interface IAuditLog
{
    void AddLog(string log);
}

public class AuditLog : IAuditLog
{
    public void AddLog(string log)
    {
        //implementation
    }
}

To call the audit log class: 调用审核日志类:

public partial class AuditLogPage : System.Web.UI.Page
{
    protected void btnAddLog_Click(object sender, EventArgs e)
    {
        IAuditLog objAuditLog = new AuditLog();
        objAuditLog.AddLog("test log");
    }
}

I still have to use AuditLog when instantiating, so what's the point? 实例化时我仍然必须使用AuditLog,所以有什么意义呢? If the AddLog method signature changes i'm still going to have to go through all my pages that use it and amend the code. 如果AddLog方法签名发生变化,我仍然必须遍历所有使用它的页面并修改代码。 Am I missing the point? 我错过了重点吗?

Thanks for any help in advance, Wilky. 谢谢您的任何提前帮助,威尔基。

In the example if you switched out FileAuditLogger() with DatabaseAuditLogger() or EventLogAuditLogger() you can switch implementations without having to rewrite your code. 在示例中,如果您使用DatabaseAuditLogger()EventLogAuditLogger()切换了FileAuditLogger() ,则可以切换实现而不必重写代码。

Typically you'd use an IoC container (Autofac, StructureMap, Unity, etc.) to automatically wire up the object instantiation. 通常,您会使用IoC容器(Autofac,StructureMap,Unity等)来自动连接对象实例化。 So instead of calling new AuditLog() you would call IoC.Container.Resolve<IAuditLog>() 因此, IoC.Container.Resolve<IAuditLog>()调用new AuditLog()IoC.Container.Resolve<IAuditLog>()调用IoC.Container.Resolve<IAuditLog>()

Let me know if you'd like more information. 让我知道您是否需要更多信息。

Let imagine that there there are two AuditLog classes 假设有两个AuditLog类

class AuditLogToDatabase : IAuditLog // writes to database

and another is 另一个是

class AuditLogToFile : IAuditLog // writes to file

like 喜欢

protected void btnAddLog_Click(object sender, EventArgs e)
{
    IAuditLog objAuditLog = AuditLogFactory.GetAuditLog();
    objAuditLog.AddLog("test log");
}

now you can inject any class based on some configuration at run time without changing the actual implementation 现在,您可以在运行时基于某些配置注入任何类,而无需更改实际实现

This doesn't necessarily mean that you have to actually use a C# interface . 这并不一定意味着您必须实际使用C# interface An interface in OOP terms is the publicly visible façade of an API. OOP术语中的接口是API的公开可见外观。 It's a contract and externally visible results of operations should be specified. 这是一项合同,应指定外部可见的操作结果。 How exactly it works beneath the surface should be irrelevant so that you can swap out the implementation at any time. 它在表面下的确切工作方式无关紧要,这样您就可以随时交换实现。

Of course, in that regard an interface is a method of being able to use different implementations, but so is an abstract base class or even a non-abstract class others can derive from. 当然,就此而言, interface是一种能够使用不同实现的方法,但是抽象基类甚至是其他人可以从中获得的非抽象类也是如此。

But more to the exact point of your question: Of course, when instantiating a class its type must be known, but you don't necessarily have to create the class instance there. 但是,更确切地说,是您的问题:当然,在实例化一个类时,必须知道其类型,但是不必一定要在该实例中创建类实例。 You could set an IAuditLog from the outside or get it via a factory class, etc. where you wouldn't know, at that exact point in the code, what exact type you're getting (except that it's compatible with IAuditLog ). 您可以从外部设置IAuditLog ,也可以通过工厂类等获取它,在代码的那个确切点上,您将不知道该类是什么类型(除了与IAuditLog兼容)。

This is actually useful when you create the AuditLog instance from a method say like a Factory method and you have more than one AuditLogXXX classes derived from the IAuditLog interface. 当您从诸如Factory方法之类的方法创建AuditLog实例,并且具有多个从IAuditLog接口派生的AuditLogXXX类时,这实际上很有用。

So, instead of using this code: 因此,不要使用此代码:

IAuditLog objAuditLog = new AuditLog();

You would actually use this code when you program to an interface: 在对接口进行编程时,实际上将使用以下代码:

IAuditLog objAuditLog = LogFactory.GetAuditLog(); //This call is programmed to an interface

where GetAuditLog() is an interface typed method defined on the LogFactory class as below: 其中GetAuditLog()是在定义的接口类型的方法LogFactory如下类:

class LogFactory
{    
    public IAuditLog GetAuditLog() // This method is programmed to an interface
    {
        //Some logic to make a choice to return appropriate AuditLogXXX instance from the factory
    }    
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM