什么是 "按接口编程,而不是按实现编程"?[英] What does "program to interfaces, not implementations" mean?

本文是小编为大家收集整理的关于什么是 "按接口编程,而不是按实现编程"?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

在阅读有关设计模式时,一个偶然发现了这句话.

但我不明白,有人可以为我解释吗?

推荐答案

接口只是合同或签名,他们不知道 关于实施的任何事情.

针对接口均值编码,客户端代码始终保存由工厂提供的接口对象.工厂返回的任何实例都是任何工厂候选类必须实现的类型接口.这样,客户端程序就不必担心实现,并且接口签名确定可以完成所有操作.这可以用于在运行时更改程序的行为.它还可以帮助您从维护的角度编写更好的程序.

这是您的基本示例.

public enum Language
{
    English, German, Spanish
}

public class SpeakerFactory
{
    public static ISpeaker CreateSpeaker(Language language)
    {
        switch (language)
        {
            case Language.English:
                return new EnglishSpeaker();
            case Language.German:
                return new GermanSpeaker();
            case Language.Spanish:
                return new SpanishSpeaker();
            default:
                throw new ApplicationException("No speaker can speak such language");
        }
    }
}

[STAThread]
static void Main()
{
    //This is your client code.
    ISpeaker speaker = SpeakerFactory.CreateSpeaker(Language.English);
    speaker.Speak();
    Console.ReadLine();
}

public interface ISpeaker
{
    void Speak();
}

public class EnglishSpeaker : ISpeaker
{
    public EnglishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak English.");
    }

    #endregion
}

public class GermanSpeaker : ISpeaker
{
    public GermanSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak German.");
    }

    #endregion
}

public class SpanishSpeaker : ISpeaker
{
    public SpanishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak Spanish.");
    }

    #endregion
}

 alt text

这只是一个基本示例, 该原则的实际解释是 除了这个答案的范围之外.

编辑

我已经更新了上面的示例,并添加了一个摘要Speaker基类.在此更新中,我向所有扬声器添加了一个功能,向" Sayhello"添加了功能.所有演讲者都说" Hello World".因此,这是具有相似功能的常见功能.请参阅类图,您会发现Speaker抽象类实施ISpeaker接口并将Speak()标记为摘要,这意味着每个说话者实现都负责实现Speak()方法,因为它因<

考虑SpanishSpeaker不能打招呼的情况,在这种情况下,您可以覆盖西班牙语者的SayHello()方法并提出适当的例外.

请注意,我们有 没有对接口进行任何更改 Ispeaker.以及客户端代码和 扬声器还不受影响 不变.这就是我们通过编程到接口.

实现的目标

,我们可以通过简单地在每个实现中添加基本的抽象类扬声器和一些较小的修改来实现这种行为,从而使原始程序保持不变.这是任何应用程序的所需功能,它使您的应用程序易于维护.

public enum Language
{
    English, German, Spanish
}

public class SpeakerFactory
{
    public static ISpeaker CreateSpeaker(Language language)
    {
        switch (language)
        {
            case Language.English:
                return new EnglishSpeaker();
            case Language.German:
                return new GermanSpeaker();
            case Language.Spanish:
                return new SpanishSpeaker();
            default:
                throw new ApplicationException("No speaker can speak such language");
        }
    }
}

class Program
{
    [STAThread]
    static void Main()
    {
        //This is your client code.
        ISpeaker speaker = SpeakerFactory.CreateSpeaker(Language.English);
        speaker.Speak();
        Console.ReadLine();
    }
}

public interface ISpeaker
{
    void Speak();
}

public abstract class Speaker : ISpeaker
{

    #region ISpeaker Members

    public abstract void Speak();

    public virtual void SayHello()
    {
        Console.WriteLine("Hello world.");
    }

    #endregion
}

public class EnglishSpeaker : Speaker
{
    public EnglishSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        this.SayHello();
        Console.WriteLine("I speak English.");
    }

    #endregion
}

public class GermanSpeaker : Speaker
{
    public GermanSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        Console.WriteLine("I speak German.");
        this.SayHello();
    }

    #endregion
}

public class SpanishSpeaker : Speaker
{
    public SpanishSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        Console.WriteLine("I speak Spanish.");
    }

    public override void SayHello()
    {
        throw new ApplicationException("I cannot say Hello World.");
    }

    #endregion
}

 alt text

其他推荐答案

将接口视为对象与其客户端之间的合同.那是指定对象可以做的事情以及访问这些东西的签名.

实现是实际行为.例如,您有一个方法stort().您可以实现QuickSort或Mergesort.只要界面不更改,对客户端代码调用排序都不重要.

诸如Java API和.NET框架之类的库可以大量使用接口,因为数百万程序员使用提供的对象.这些库的创建者必须非常小心,以免它们将界面更改为这些库中的类,因为它将使用库影响所有程序员.另一方面,他们可以尽可能多地更改实现.

如果作为程序员,您可以反对实现,一旦更改代码就停止工作.因此,以这种方式考虑界面的好处:

  1. 它隐藏了您不需要知道使对象更简单使用的事物.
  2. 它提供了对象的行为方式的合同,因此您可以依靠

其他推荐答案

这意味着您应该尝试编写代码,以便使用抽象(抽象类或接口)而不是直接实现.

通常,该实现通过构造函数或方法调用注入您的代码.因此,您的代码知道接口或抽象类,并可以调用本合同中定义的任何内容.作为实际对象(使用接口/摘要类的实现),调用在对象上运行.

这是 Liskov Substitution Principle (lsp),< SOLID 原理.

.net中的一个示例是使用IList代码而不是List或Dictionary,因此您可以在代码中互换实现IList的任何类:

// myList can be _any_ object that implements IList
public int GetListCount(IList myList)
{
    // Do anything that IList supports
    return myList.Count();
}

基类库(BCL)的另一个示例是 ProviderBase 抽象类 - 这提供了一些基础架构,并且重要的是,如果您反对代码,则可以互换使用所有提供商.

本文地址:https://www.itbaoku.cn/post/627451.html

问题描述

One stumbles upon this phrase when reading about design patterns.

But I don't understand it, could someone explain this for me?

推荐答案

Interfaces are just contracts or signatures and they don't know anything about implementations.

Coding against interface means, the client code always holds an Interface object which is supplied by a factory. Any instance returned by the factory would be of type Interface which any factory candidate class must have implemented. This way the client program is not worried about implementation and the interface signature determines what all operations can be done. This can be used to change the behavior of a program at run-time. It also helps you to write far better programs from the maintenance point of view.

Here's a basic example for you.

public enum Language
{
    English, German, Spanish
}

public class SpeakerFactory
{
    public static ISpeaker CreateSpeaker(Language language)
    {
        switch (language)
        {
            case Language.English:
                return new EnglishSpeaker();
            case Language.German:
                return new GermanSpeaker();
            case Language.Spanish:
                return new SpanishSpeaker();
            default:
                throw new ApplicationException("No speaker can speak such language");
        }
    }
}

[STAThread]
static void Main()
{
    //This is your client code.
    ISpeaker speaker = SpeakerFactory.CreateSpeaker(Language.English);
    speaker.Speak();
    Console.ReadLine();
}

public interface ISpeaker
{
    void Speak();
}

public class EnglishSpeaker : ISpeaker
{
    public EnglishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak English.");
    }

    #endregion
}

public class GermanSpeaker : ISpeaker
{
    public GermanSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak German.");
    }

    #endregion
}

public class SpanishSpeaker : ISpeaker
{
    public SpanishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak Spanish.");
    }

    #endregion
}

alt text

This is just a basic example and actual explanation of the principle is beyond the scope of this answer.

EDIT

I have updated the example above and added an abstract Speaker base class. In this update, I added a feature to all Speakers to "SayHello". All speaker speak "Hello World". So that's a common feature with similar function. Refer to the class diagram and you'll find that Speaker abstract class implement ISpeaker interface and marks the Speak() as abstract which means that the each Speaker implementation is responsible for implementing the Speak() method since it varies from Speaker to Speaker. But all speaker say "Hello" unanimously. So in the abstract Speaker class we define a method that says "Hello World" and each Speaker implementation will derive the SayHello() method.

Consider a case where SpanishSpeaker cannot Say Hello so in that case you can override the SayHello() method for Spanish Speaker and raise proper exception.

Please note that, we have not made any changes to Interface ISpeaker. And the client code and SpeakerFactory also remain unaffected unchanged. And this is what we achieve by Programming-to-Interface.

And we could achieve this behavior by simply adding a base abstract class Speaker and some minor modification in Each implementation thus leaving the original program unchanged. This is a desired feature of any application and it makes your application easily maintainable.

public enum Language
{
    English, German, Spanish
}

public class SpeakerFactory
{
    public static ISpeaker CreateSpeaker(Language language)
    {
        switch (language)
        {
            case Language.English:
                return new EnglishSpeaker();
            case Language.German:
                return new GermanSpeaker();
            case Language.Spanish:
                return new SpanishSpeaker();
            default:
                throw new ApplicationException("No speaker can speak such language");
        }
    }
}

class Program
{
    [STAThread]
    static void Main()
    {
        //This is your client code.
        ISpeaker speaker = SpeakerFactory.CreateSpeaker(Language.English);
        speaker.Speak();
        Console.ReadLine();
    }
}

public interface ISpeaker
{
    void Speak();
}

public abstract class Speaker : ISpeaker
{

    #region ISpeaker Members

    public abstract void Speak();

    public virtual void SayHello()
    {
        Console.WriteLine("Hello world.");
    }

    #endregion
}

public class EnglishSpeaker : Speaker
{
    public EnglishSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        this.SayHello();
        Console.WriteLine("I speak English.");
    }

    #endregion
}

public class GermanSpeaker : Speaker
{
    public GermanSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        Console.WriteLine("I speak German.");
        this.SayHello();
    }

    #endregion
}

public class SpanishSpeaker : Speaker
{
    public SpanishSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        Console.WriteLine("I speak Spanish.");
    }

    public override void SayHello()
    {
        throw new ApplicationException("I cannot say Hello World.");
    }

    #endregion
}

alt text

其他推荐答案

Think of an interface as a contract between an object and its clients. That is the interface specifies the things that an object can do, and the signatures for accessing those things.

Implementations are the actual behaviours. Say for example you have a method sort(). You can implement QuickSort or MergeSort. That should not matter to the client code calling sort as long as the interface does not change.

Libraries like the Java API and the .NET Framework make heavy use of interfaces because millions of programmers use the objects provided. The creators of these libraries have to be very careful that they do not change the interface to the classes in these libraries because it will affect all programmers using the library. On the other hand they can change the implementation as much as they like.

If, as a programmer, you code against the implementation then as soon as it changes your code stops working. So think of the benefits of the interface this way:

  1. it hides the things you do not need to know making the object simpler to use.
  2. it provides the contract of how the object will behave so you can depend on that

其他推荐答案

It means that you should try to write your code so it uses an abstraction (abstract class or interface) instead of the implementation directly.

Normally the implementation is injected into your code through the constructor or a method call. So, your code knows about the interface or abstract class and can call anything that is defined on this contract. As an actual object (implementation of the interface/abstract class) is used, the calls are operating on the object.

This is a subset of the Liskov Substitution Principle (LSP), the L of the SOLID principles.

An example in .NET would be to code with IList instead of List or Dictionary, so you could use any class that implements IList interchangeably in your code:

// myList can be _any_ object that implements IList
public int GetListCount(IList myList)
{
    // Do anything that IList supports
    return myList.Count();
}

Another example from the Base Class Library (BCL) is the ProviderBase abstract class - this provides some infrastructure, and as importantly means all provider implementations can be used interchangeably if you code against it.