【问题标题】:How to define 'public' and 'private' interfaces to an object?如何定义对象的“公共”和“私有”接口?
【发布时间】:2011-07-29 02:52:48
【问题描述】:

我有一个数据库和一个 DAL 类来管理对象到数据(反之亦然)的映射,其方式与实体框架类似——但我们还不能在这里使用 EF,所以 DAL 是一个相当简单的自制库,它公开了一些对象并允许对它们执行操作。它有效,并且会一直有效,直到我们可以找到一个“合适的”EF 解决方案。

DAL 为“客户端”应用程序提供了各种对象,并定义了方法和属性来封装每个操作的逻辑并隐藏这些对象的内部状态以及将它们持久保存到数据库所需的机制。这也有效。

但是,DAL 的对象接口公​​开了一些真正应该是“私有”的操作 - 它们由在其他地方运行的服务应用程序使用,对数据库中的对象执行各种后台操作。我真的不希望“客户端”应用程序能够看到这些方法,但我确实希望在服务应用程序引用 DAL 时这些方法可见。

当前实现示例:

DAL Library
  Object
    Method LoadObject()
    Method SaveObject()
    Method AdjustInternalObjectProperty()

因此,客户端应用程序可以看到所有三种方法,尽管它们不应该使用第三种方法 - 这是一个只对服务应用程序可见的功能(应该能够看到和使用所有三种方法)。

所以问题是,最好的方法是什么,既可以保留对每个对象使用接口的意图,又可以“隐藏”该接口的某些部分,并且只使隐藏的部分可供适当“友好”的人访问服务应用程序。是否有一些访问修饰符技术可以让我将界面的某些部分设为“私有”,并使用服务应用程序使用(但客户端没有)访问这些私有元素的机制?或者这是一个应该存在两个不同接口的场景,其中“客户端”接口只是省略了“内部”方法?还是别的什么?

我想以“正确”的方式做到这一点 - 我搜索了 SO 并找到了一堆关于多个对象接口的已回答问题,但似乎没有一个能完全解决我的具体问题。如果有 现有答案,请务必指出我并关闭此问题。

编辑(在阅读答案和实验后):

using System;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Test")]

namespace Interface_Test
{
  public interface IStandard
  {
    void StandardMethod();
  }
  internal interface ISuper : IStandard
  {
    void SuperMethod();
  }

  public sealed class TestClass : ISuper
  {
    public void StandardMethod()
    {
      Console.WriteLine("The standard method");
    }
    void ISuper.SuperMethod()
    {
      Console.WriteLine("The super method");
    }
  }
}

这可以完成工作 - 大部分对象暴露是通过 IStandard 接口,这是任何和所有客户端程序集都可以使用的沼泽标准公共接口。 “受限制”的东西只能通过备用的ISuper 接口访问,它继承了IStandard 的所有核心内容,但添加了我只希望特定“服务客户端”使用的额外项目。通过按照建议添加[InternalsVisibleTo] 属性,此接口及其方法/属性对除命名程序集以外的所有程序都是完全不可见的。

缺点是有两个接口,但在没有语言工具的情况下,例如允许 'internal' 作为接口方法定义的修饰符,这是确保客户端程序集无法使用接口支持的功能的合理方法但不是一般用途。

【问题讨论】:

    标签: c# interface


    【解决方案1】:

    一个选项是:

    • 创建internal接口
    • 显式地实现(以避免需要公共方法)
    • 使用[InternalsVisibleTo] 让您的“服务应用程序”访问内部接口

    您可能对this blog post 感兴趣,它为其他情况显示了一些有趣的选项。

    【讨论】:

    • 是的,这会起作用,但这看起来像一个 .NET hack,而我认为这需要 融入接口,因为这是 设计的一部分.
    • @Aliostad:我不确定我是否真的称它为“黑客”......它正在将其烘焙到接口中,拥有一个内部 API 和一个公共的。
    • 这加上接口继承答案给了我一个解决方案 - 答案被接受。 :)
    【解决方案2】:

    一种常见的方法是使用 2 个接口:

    public interface IBar
    {
       void DoSimpleStudd();
       int This {get;}
    
    }
    
    public interface ISuperBar : IBar
    {
       void DoComplexStuff();
       int That {get; set;}
    
    }
    
    // at service layer
    public class ServiceWidget
    {
        public ISuperBar Bar {get; set;}
        ...
    }
    
    // other places
    public class ServiceWidget
    {
        public IBar Bar {get; set;}
        ...
    }
    

    所以在service layer 中,他们将使用ISuperBar,而在应用程序的其他部分,他们将使用IBar

    更新

    是的,接口是公开的。

    【讨论】:

    • 这些是公共接口吗?如果是这样,如何从客户端应用程序中隐藏 ISuperBar?类要么实现它,要么不实现。
    • @Jon 是的,它们是公开的——我只是在表达观点时省略了这一点。它不会被隐藏。 IoC 将被配置为返回相同的实现,但在 UI 中,依赖项将是 IBar,而服务对象将引用 ISuperBar
    • @Aliostad:甚至没有提到 IoC,这有点不清楚 :) 我仍然认为这不符合既定目标“仅使隐藏部分可供适当'友好'的服务应用程序访问” .在我看来,任何应用程序都可以请求更强大的界面。
    • @Job 谢谢乔恩,感谢您的意见。我将可见性视为对象交互设计中的一个概念——与语言中立——因此会坚持基本的 OO 原则,而不是使用语言特性来修复它。但正如我所说,您的方法完全有效并解决了问题。
    • +1 因为这与接受的答案相结合,为我提供了解决方案。 :)
    猜你喜欢
    • 1970-01-01
    • 2014-09-21
    • 1970-01-01
    • 2012-05-14
    • 2017-10-11
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多