创建对象而不破坏封装

时间:2009-04-03 11:02:15

标签: c# oop

我对这一切都很陌生,所以这可能是OOP 101,但我无法理解它,假设以下C#代码存在于程序集中:

internal interface IDataStore
{
    void Store(string name, object data);
    object Retrieve(string name);
}

internal class DBStore : IDataStore
{
    public DBStore(string connection) { }
    public void Store(string name, object data) { }
    public object Retrieve(string name) { }
}

public class GizmoManager
{
    public GizmoManager(IDataStore dataStore) { }
    // Other stuff
}

public class WidgetManager
{
    public WidgetManager(IDataStore dataStore) { }
    // Other stuff
}

如果第二个程序集试图创建一个GizmoManager和一个WidgetManager,它就不能,因为它无法获取DBStore(因为它是内部的而不是公共的)。

以下不适用AFAICS:

  • 公开DBStore和IDataStore。不好,因为客户端程序集可以绕过GizmoManager / WidgetManager并访问它喜欢的数据库。
  • 不要将IDataStore传递给GizmoManager和WidgetManager构造函数。不好因为它降低了可测试性(你不能轻易传入MockDataStore)。
  • 与工厂做一些神奇的事情。似乎没有解决任何问题,因为你需要将相同的IDataStore传递给GizmoManager和WidgetManager,因此客户端程序集仍然需要将一个IDataStore分配给一个变量(它不能,因为IDataStore是内部的)。

这可能非常明显,但我看不到它。如何克服这一矛盾?

TIA。

5 个答案:

答案 0 :(得分:3)

只需将界面IDataStore公开。这样,客户端可以使用他们自己创建的模拟对象来实例化您的WidgetManagerGizmoManager类。

实现 Factory 类设计模式,以允许通过客户端代码创建GiszmoManagerWidgetManager对象。这样,客户端代码永远不会创建DBStore对象,因此他们永远不会绕过您的经理。

顺便说一句为什么要烦恼封装?如果您在专有框架业务中,这可能有意义,但除此之外,YAGNI

答案 1 :(得分:1)

将IDataStore和DBStore公开,但将DBStore构造函数设为内部。然后可以说,1完全控制DBStores何时被实例化,但程序集2能够访问并传入DBStore。

我想你会在程序集1中想要一个工厂,它限制了创建的DBStore实例的数量或配置。

答案 2 :(得分:0)

您可以创建接口和类public,但可以使方法直接访问数据库internal。这样,您可以实例化DBStore的实例,而不允许对不允许其他程序集的方法进行任何访问。

internal方法仅对同一程序集中的类可见。

我宁愿检查是否无法组装对象而无需每次都实例化DBStore。也许工厂模式或依赖注入?然后,您可以将您的界面公开,并让第一个程序集中的工厂实例化它们。这不会影响可测试性,但会减少您创建的对象实例。较少new XYZ()次陈述更好......

答案 3 :(得分:0)

让DBStore公开,但是要让你不想公开私人或内部的所有成员。然后... 选项1:从IDataStore中删除您不希望在程序集外部访问的所有成员,并将IDataStore公开。 选项2:将IDataStore重命名为IDataStoreInternal,并使其继承自没有成员的新公共IDataStore接口(或者只是要在外部公开的成员)。

答案 4 :(得分:0)

我喜欢这两个:

  
      
  • 不要将IDataStore传递给GizmoManager和WidgetManager   构造函数。不好因为它减少了   可测试性(你不能轻易传入   一个MockDataStore)。
  •   
  • 与工厂做一些神奇的事情。似乎没有解决任何问题,因为   你需要传递相同的IDataStore   同时使用GizmoManager和WidgetManager   因此客户端组件仍然   需要将IDataStore分配给   变量(它不能因为   IDataStore是内部的。
  •   

为了解决可测试性但隐藏实现,公共接口应该只提供商店是否应该是实时的,可测试的,预生产等的选项。因此,您可以将正确的IDataStore构造的责任委托给程序集内的另一方。例如。工厂概念,只允许您设置“测试”,“部署”,“调试”等。在给定“模式”设置的情况下,使用默认构造函数(或单例或其他)在工厂内部引用正确的存储。 / p>