如何最好地组织类和接口文件?


17

好的..经过所有讨论之后,我将稍微更改我的问题以更好地反映我正在处理的具体示例。


我有两个类,ModelOneModelTwo,这些类执行类似的功能,但彼此无关。但是,我有一个第三类CommonFunc,其中包含一些公共功能,这两种功能都在两者中实现ModelOneModelTwo并且已根据进行了分解DRY。这两个模型是在ModelMain类中实例化的(它本身是在更高级别上实例化的,但是我将在这个级别上停止)。

我正在使用的IoC容器是Microsoft Unity。我不假装自己是专家,但是我的理解是,您在容器中注册了一个接口和类的元组,当您想要一个具体的类时,您会向IoC容器询问与特定接口匹配的任何对象。这意味着对于我要从Unity实例化的每个对象,都必须有一个匹配的接口。因为我的每个类都执行不同的功能(且不重叠),所以这意味着接口和类1之间的比例为1:1。但是,这并不意味着我正在为每个编写的类都刻苦地编写一个接口。

因此,在代码方面,我最终得到2

public interface ICommonFunc 
{ 
}

public interface IModelOne 
{ 
   ICommonFunc Common { get; } 
   .. 
}

public interface IModelTwo
{ 
   ICommonFunc Common { get; } 
   .. 
}

public interface IModelMain 
{ 
  IModelOne One { get; } 
  IModelTwo Two { get; } 
  ..
}

public class CommonFunc : ICommonFunc { .. }

public class ModelOne : IModelOne { .. }

public class ModelTwo : IModelTwo { .. }

public class ModelMain : IModelMain { .. }

问题是关于如何组织我的解决方案。我应该将类和接口保持在一起吗?还是应该将类和接口保持在一起?例如:

选项1- 按班级名称组织

MySolution
  |
  |-MyProject
  |   |
      |-Models
      |   |
          |-Common
          |   |
          |   |-CommonFunc.cs
          |   |-ICommonFunc.cs
          |
          |-Main
          |   |
          |   |-IModelMain.cs
          |   |-ModelMain.cs
          |
          |-One
          |   |
          |   |-IModelOne.cs
          |   |-ModelOne.cs
          |
          |-Two
              |
              |-IModelTwo.cs
              |-ModelTwo.cs
              |

选项2-按功能组织(主要)

MySolution
  |
  |-MyProject
  |   |
      |-Models
      |   |
          |-Common
          |   |
          |   |-CommonFunc.cs
          |   |-ICommonFunc.cs
          |
          |-IModelMain.cs
          |-IModelOne.cs
          |-IModelTwo.cs
          |-ModelMain.cs
          |-ModelOne.cs
          |-ModelTwo.cs
          |

选项3-分离接口和实现

MySolution
  |
  |-MyProject
      |
      |-Interfaces
      |   |
      |   |-Models
      |   |   |
      |       |-Common
      |       |   |-ICommonFunc.cs
      |       |
      |       |-IModelMain.cs
      |       |-IModelOne.cs
      |       |-IModelTwo.cs
      |
      |-Classes
          | 
          |-Models
          |   |
              |-Common
              |   |-CommonFunc.cs
              |
              |-ModelMain.cs
              |-ModelOne.cs
              |-ModelTwo.cs
              |

选项4-进一步介绍功能示例

MySolution
  |
  |-MyProject
  |   |
      |-Models
      |   |
          |-Components
          |   |
          |   |-Common
          |   |   |
          |   |   |-CommonFunc.cs
          |   |   |-ICommonFunc.cs
          |   |   
          |   |-IModelOne.cs
          |   |-IModelTwo.cs
          |   |-ModelOne.cs
          |   |-ModelTwo.cs
          |
          |-IModelMain.cs
          |-ModelMain.cs
          |

我有点不喜欢选项1,因为路径中的类名。但正如我倾向于1:1分的比例,因为我选择的IoC /使用的(并且可能是有争议的)这种在看到文件之间的关系优势。

选项2对我很有吸引力,但现在我已经使ModelMain和子模型之间的水变得浑浊。

选项3可以将接口定义与实现分开,但是现在我在路径名中有这些人为的中断。

选项4。我选择了选项2并对其进行了调整,以将组件与父模型分离。

是否有充分的理由偏爱一个?还是我错过的任何其他潜在布局?


弗兰克(Frank)发表评论说,比率为1:1可以追溯到.h和.cpp文件的C ++天。我知道他从哪里来。我对Unity的理解似乎使我陷入了困境,但是如果您也遵循Program to an interface But 的说法,那我什至不知道如何摆脱困境。

2.我省略了每个对象构造函数的详细信息。这是IoC容器根据需要注入对象的地方。


1
啊。闻起来您的接口/类比率为1:1。您正在使用哪个IoC容器?Ninject提供了不需要1:1比例的机制。
RubberDuck

1
@RubberDuck FWIW我正在使用Unity。我不主张在这方面的专家,但如果我的类以及单责任设计,我怎么几乎一1结束了:1的比例?
彼得M,

您需要IBase还是基础可以抽象?为什么IDerivedOne已经实现了IBase?您应该依赖于IBase,而不是派生的。我对Unity不了解,但是其他IoC容器允许您进行“上下文敏感”注入。基本上在Client1需要IBase时提供一个Derived1。当Client2需要时IBase,IoC提供一个Derived2
RubberDuck

1
好吧,如果base是抽象的,那么就没有理由要interface它了。An interface实际上只是具有所有虚拟成员的抽象类。
RubberDuck

1
RubberDuck是正确的。多余的接口很烦人。
Frank Hileman '17

Answers:


4

由于接口抽象上类似于基类,因此请使用与基类相同的逻辑。实现接口的类与该接口紧密相关。

我怀疑您是否希望使用一个名为“基础类”的目录;大多数开发人员都不想这样做,也不需要目录“ Interfaces”。在c#中,目录在默认情况下也是命名空间,这使它倍加混乱。

最好的方法是考虑如果必须将类/接口放入单独的库中,并以类似的方式组织名称空间/目录,将如何分解类/接口。.net框架设计指南中的命名空间建议可能会有所帮助。


我对您提供的链接有点熟悉,但是我不确定它与文件组织之间的关系。虽然VS默认使用初始名称空间的路径名,但我知道这是一个任意选择。另外,我还更新了代码“示例”和布局可能性。
Peter M

@PeterM我不确定您使用的是哪个IDE,但是例如,在添加类时,Visual Studio会使用目录名称自动生成名称空间声明。这意味着虽然目录名称和名称空间名称之间可能会有区别,但是以这种方式工作更痛苦。因此,大多数人不这样做。
Frank Hileman '17

我正在使用VS。是的,我知道痛苦。它带回了Visual Source Safe文件布局的记忆。
彼得M

1
@PeterM关于1:1接口与类的比率。一些工具需要这样做。我认为这是该工具的缺陷-.net具有足够的反射功能,因此不需要任何此类工具中的此类限制。
Frank Hileman '17

1

我确实采用第二种方法,当然在复杂项目中还有更多文件夹/命名空间。这意味着我将接口与具体实现分离。

在不同的项目中,您可能必须知道接口定义,但是根本不需要知道实现它的任何具体类-尤其是在使用IoC容器时。因此,那些其他项目仅需要引用接口项目,而无需引用实现项目。这可以使引用保持较低,并可以防止循环引用问题。


我已经修改了代码示例并添加了更多选项
Peter M

1

与任何设计问题一样,首先要做的就是确定谁是您的用户。他们将如何使用您的组织?

他们是将使用您的课程的编码员吗?然后最好将接口与代码分开。

他们是您代码的维护者吗?然后将接口和类保持在一起可能是最好的。

坐下来并创建一些用例。然后,最好的组织可能会出现在您面前。


-2

我认为最好将接口存储在单独的库中。首先,这种设计增加了依赖性。这就是为什么可以通过另一种编程语言来实现这些接口的原因。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.