C# 界面分离原理及应用
这种情况发生在我身上很多次,我不知道如何解决它 这是为了防止出现一些情况,当一些接口实现不使用它的功能时——这是显而易见的。通常情况下,我有一个接口列表,我想用它们做点什么。让我们看一个没有ISP的例子:C# 界面分离原理及应用,c#,convention,interface-segregation-principle,C#,Convention,Interface Segregation Principle,这种情况发生在我身上很多次,我不知道如何解决它 这是为了防止出现一些情况,当一些接口实现不使用它的功能时——这是显而易见的。通常情况下,我有一个接口列表,我想用它们做点什么。让我们看一个没有ISP的例子: public interface IPerson { void Run(); void Eat(); } public class AbcPerson : IPerson { void Run(){};
public interface IPerson
{
void Run();
void Eat();
}
public class AbcPerson : IPerson
{
void Run(){};
void Eat(){};
}
public class XyzPerson : IPerson
{
void Run(){};
void Eat(){};
}
List<IPerson> People {get;set;}
现在我想和他们一起吃饭
foreach(var person in People)
{
person.Eat();
}
现在,如果我想使用ISP,我应该将代码更改为:
public interface IRunnable
{
void Run();
}
public interface IEatable
{
void Eat();
}
public class AbcPerson : IRunnable,IEatable
{
void Run(){};
void Eat(){};
}
public class XyzPerson : IRunnable,IEatable
{
void Run(){};
void Eat(){};
}
我应该如何列出我的名单?我是否应该列出两个可运行和可吃的列表,并添加对象(丑陋),或者第二种方法-创建一个列表,如果可能的话,将它们强制转换(丑陋)?我不知道这样做的最佳惯例是什么
这个例子也许不是我能想象的最好的例子,但我希望你明白我的意思
编辑:我更改了接口、类和原则名称。如果您的系统中有运行和使用的东西,请将其定义为接口:
public interface IHungryRunner : IRunnable, IEatable
{ }
public interface IPerson : IRunnable, IEatable {}
假设IRunnable和IEatable将单独使用,否则就将它们放在一起
您还可以维护iRunTables和iDataTables的单独列表,而不是试图将它们放在一起。软件体系结构中的每一条规则、惯例和设计模式都应该谨慎对待。您需要考虑为什么某些东西被视为规则/约定/设计模式,以便知道何时应用它 根据: 让一个班级专注于一个问题是很重要的 它使类更加健壮。继续[…生成报告并打印…]示例,如果报告编译过程发生更改,则 如果打印代码是系统的一部分,则其损坏的危险更大 同一个班级 这里的要点是生成报告的过程本质上独立于打印报告的过程。因此,应允许这些操作单独更改 在您的
Connect()
/Disconnect()
示例中,我假设这两个操作的内聚性非常强,如果其中一个操作发生更改,那么另一个操作很可能也需要更改。因此,在一个接口中组合Connect()
和Disconnect()
不会违反SRP
另一方面,如果操作是“代码> e>())/>代码> <代码> Run()>代码>,则需要考虑这两个操作的衔接。
最后:要务实!您是否希望将
Eat()
和Run()
拆分为单独的接口,以便在可预见的将来提供任何好处?否则,您可能会违反另一个设计原则:。保留IPerson界面是合理的,因为有人可能会认为跑步和吃饭都是“做人”的责任
如果您觉得定义单独的iRunTable和IEatable接口很有价值,那么您可以使用它们来定义IPerson接口:
public interface IHungryRunner : IRunnable, IEatable
{ }
public interface IPerson : IRunnable, IEatable {}
这有点脱离了问题的单一责任方面,但我感觉这可能是进退两难的一部分:如果您有其他代码只关心事物的“可运行”方面,那么您可以有一个接受IEnumerable
参数的方法。通过.NET 4中引入的协方差规则,您的列表
对象是一个IEnumerable
,因此您可以简单地传递它而无需任何强制转换
void DoSomethingWithRunnables(IEnumerable<IRunnable> runnables)
{
...
foreach (var item in runnables)
{
item.Run();
}
...
}
void DoSomethingWithRunnables(IEnumerable runnables)
{
...
foreach(可运行项中的变量项)
{
item.Run();
}
...
}
我不认为在同一个接口中使用连接
和断开
会违反SRP。你应该把你的界面描述成比IConnect
更一般的东西,也许可以描述你的产品,比如IDevice
,它们可以一起生活在一起是的,这就是为什么我写这不是一个完美的例子。它应该是非常不同的东西,比如Eat()和Run(),我将编辑它的RP是“只做一件事”的原则,我在这里看不到接口的链接。它与ISP也没有太大关系,因为您使用的是所有的方法。。我想说这更像是一个OCP案例,但这实际上取决于系统以后可能会如何变化,我们不知道。是的,你完全正确。我把名字拼错了。我的意思是接口分离原则您可以添加第三个接口来继承这两个接口。此外,将成员直接从IPerson
重构为IPerson:IEatable,IRunnable
,这是毫无痛苦的,因为引用IPerson
的类都不需要更改