代码之家  ›  专栏  ›  技术社区  ›  chills42

使用显式接口以确保针对接口编程

  •  8
  • chills42  · 技术社区  · 16 年前

    我已经看到使用显式接口作为将类使用锁定到该接口的方法的参数。理由似乎是,通过强制其他人编程到接口,您可以确保更好地分离类,并允许更简单的测试。

    例子:

    public interface ICut
    {
        void Cut();
    }
    public class Knife : ICut
    {
        void ICut.Cut()
        {
            //Cut Something
        }
    }
    

    并且要使用刀对象:

    ICut obj = new Knife();
    obj.Cut();
    

    您会推荐这种接口实现方法吗?为什么或为什么不呢?

    编辑: 另外,考虑到我正在使用一个显式接口,下面的内容将不起作用。

    Knife obj = new Knife();
    obj.Cut();
    
    11 回复  |  直到 16 年前
        1
  •  4
  •   erlando    16 年前

    引用GOF第1章:

    • “程序到接口,而不是实现”。
    • “优先使用对象组合而不是类继承”。

    因为C没有多重继承,所以对象组合和接口编程是一种方法。

    埃塔:无论如何,您不应该使用多重继承,但这是另外一个主题。-)

    eta2:我不太确定显式接口。这似乎不具有建设性。为什么我要有一把刀,只有当重症监护室时才能切?

        2
  •  3
  •   ilitirit    16 年前

    我只在希望限制访问某些方法的场景中使用它。

    public interface IWriter
    {
        void Write(string message);
    }
    
    public interface IReader
    {
        string Read();
    }
    
    public class MessageLog : IReader, IWriter
    {
          public string Read()
          {
               // Implementation
    
              return "";
          }
    
          void IWriter.Write(string message)
          {
               // Implementation
          }
    }
    
    public class Foo
    {
        readonly MessageLog _messageLog;
        IWriter _messageWriter;
    
        public Foo()
        {
             _messageLog = new MessageLog();
             _messageWriter = _messageLog;
        }
    
        public IReader Messages
        {
            get { return _messageLog; }
        }
    }
    

    现在,foo可以使用messagewriter将消息写入其消息日志,但客户机只能读取消息。在类可见的情况下,这尤其有用。您的客户端无法强制转换为编写器类型并更改消息日志中的信息。

        3
  •  2
  •   Mitch Wheat    16 年前

    对。不仅仅是为了测试。将公共行为考虑到接口(或抽象类)中是有意义的;这样就可以利用多态性。

    public class Sword: ICut
    {    
      void ICut.Cut()   
      {        
         //Cut Something   
      }
    }
    

    工厂可以退回一种锋利的工具!:

    ICut obj = SharpImplementFactory();
    
    obj.Cut();
    
        4
  •  2
  •   dpurrington    16 年前

    这是一个坏主意,因为它们的使用打破了多态性。使用的引用类型不应改变对象的行为。如果要确保松耦合,请将类设置为内部类并使用DI技术(如Spring.net)。

        5
  •  2
  •   yfeldblum    16 年前

    毫无疑问,强制代码用户将对象强制转换为您希望它们使用的接口类型具有某些优势。

    但是,总体而言,接口编程是一个方法论或过程问题。编程到一个接口并不是仅仅通过让你的代码让用户讨厌来实现的。

        6
  •  1
  •   Nick    16 年前

    在这个方法中使用接口本身并不会导致代码分离。如果这就是您所做的全部工作,那么它只会添加另一层模糊,并可能在稍后使这一层更加混乱。

    但是,如果您将基于接口的编程与控制反转和依赖注入结合起来,那么您真的会有所收获。如果您要进行测试驱动的开发,您还可以使用这种类型的设置对单元测试使用模拟对象。

    然而,国际奥委会、DI和TDD本身都是主要的主题,而且所有的书都是关于这些主题的。希望这会给你一个可以研究的起点。

        7
  •  1
  •   Steve g    16 年前

    嗯,这是一个组织优势。您可以将ICuttingSurface、ICUT和相关功能封装到一个可自我包含和单元测试的程序集中。ICUT接口的任何实现都很容易被模仿,并且可以仅依赖于ICUT接口而不是实际的实现,这使得系统更加模块化和干净。

    这也有助于保持继承更简单,并给您更多的灵活性,以使用多道手术。

        8
  •  1
  •   Krypes    16 年前

    只允许期望显式接口类型的调用方,确保方法仅在所需的上下文中可见。

    考虑一个游戏中的逻辑实体,你决定,你希望实体中有记号/画的代码,而不是绘制/勾选实体的类责任。

    实现idrawable.draw()和itickable.tick()确保实体只能在游戏预期的时候被绘制/标记。否则,这些方法将永远不可见。

    较小的好处是在实现多个接口时,显式实现允许您处理两个接口方法名冲突的情况。

        9
  •  1
  •   Michael Carman    16 年前

    显式实现接口的另一个潜在方案是处理已经实现功能但使用不同方法名的现有类。例如,如果刀类已经有了一个名为slice的方法,那么可以通过以下方式实现接口:

    public class Knife : ICut
    {
         public void Slice()
         {
              // slice something
         }
    
         void ICut.Cut()
         {
              Slice();
         }
    }
    
        10
  •  0
  •   skaffman    16 年前

    如果客户机代码不关心它可以使用对象 Cut() 东西,然后用 ICut .

        11
  •  0
  •   Jeff    16 年前

    是的,但不一定是因为给定的原因。

    一个例子:

    在我当前的项目中,我们正在构建一个用于数据输入的工具。我们有一些功能被所有(或几乎所有)选项卡使用,并且我们正在对单个页面(项目是基于Web的)进行编码,以包含所有数据输入控件。

    此页面上有导航,以及与所有常见操作交互的按钮。

    通过定义一个为每个函数实现方法的接口(IDataEntry),并在每个控件上实现该接口,我们可以在执行实际数据输入的用户控件上使用aspx页面fire public方法。

    通过定义一组严格的交互方法(例如示例中的“cut”方法),接口允许您获取一个对象(无论是业务对象、Web控件还是您拥有的对象)并以定义的方式使用它。

    例如,你可以称之为切割任何ICUT对象,无论是刀,锯子,喷灯,或单丝电线。

    为了测试的目的,我认为接口也很好。如果您基于接口的预期功能定义测试,那么您可以按照描述定义对象并测试它们。这是一个非常高级的测试,但它仍然确保了功能性。但是,这不应该取代对单个对象方法的单元测试……如果“obj.cut”导致错误的对象被切割,或者在错误的位置切割,那么不好知道“obj.cut”会导致切割。