我有一个预订系统,它允许您预订、修改现有预订和取消现有预订。我正在研究接口隔离原则,我想知道我应该把我的接口做得多薄,如果我违反了单一职责原则。我最初的设计是:
interface IReservation
{
void Book();
void Modify();
void Cancel();
}
,但后来我想,如果一个预订系统不需要为预订实现这些方法之一,而只与预订有关,那么我做了以下操作:
interface IBook
{
void Book();
}
interface IModify
{
void Modify();
}
interface ICancel
{
void Cancel();
}
现在我可以这样做:
interface IReservation : IBooking
{
}
或
interface IReservation : IBooking, IModify
{
}
所以问题就变成了我是不是把它弄得太薄了。此外,为接口命名也变得更加困难,例如,我不喜欢IModify或ICancel(对我来说,它们就像是应该在IReservation接口上的方法)。如何决定什么应该进入一个接口,什么应该被隔离到另一个接口、类等……
在查看接口的作用域时必须考虑两件事:
- 要求每个
IReservation
实现这些成员有意义吗? - 不引用成员
Y
而引用成员X
有意义吗?
第一个是你已经涵盖的内容,并且得出了"不"的结论。第二点同样重要。认为某物"可以修改"而不能够做任何其他事情有意义吗?如果没有,请考虑使用IReservation
和IModifiableReservation
,或者其他一些功能分组。
例如,Cancel
和Modify
似乎是齐头并进的,所以可能想把它们都放在IModifiableReservation
上,然后让你的类实现该接口。
看起来有点太细了
我建议有两个接口
interface IBookableReservation
{
void Book();
}
和Adam Robinson的建议
interface IModifiableReservation
{
void Modify();
void Cancel();
}
你不需要创建IReservation接口,而是直接从ibookablerreservation和imodifiablelerreservation继承你的类。客户端可以使用一个接口,也可以同时使用两个接口。
没有必要创建一个接口,它只是复制一个类的公共方法。如果接口的名称与类的名称相同,只是前缀为"I",这是一种代码气味,因为它表明接口和实现它的具体类之间是1:1的关系。
参见重用抽象原则(RAP)
and from http://martinfowler.com/bliki/InterfaceImplementationPair.html
在不需要多个接口时使用接口实现是保持所有内容同步的额外工作。此外它隐藏了实际提供多个的情况实现。
如果您的应用程序确实需要支持不同类型的预订,并且以后一些公共逻辑应该能够处理所有预订—我建议为每个服务类型引入单独的接口,为每个预订本身引入单个接口,其思想—预订提供一组服务,因此您只需公开由公共接口IReservationService
抽象的服务列表,并摆脱每个预订系统的多个接口实现。只需为每个服务创建一个类,并通过Reservation函数注册服务:
var reservationWithBooking =
new Reservation(new List<IReservationService { new BookingService() });
var reservationWithCancellation =
new Reservation(new List<IReservationService { new CancellationService(); });
var mixedReservation =
new Reservation(new List<IReservationService
{
new BookingService(),
new CancellationService()
});
接口:
interface IReservationService
{
}
interface IBookingService : IReservationService
{
void Book(...);
}
interface ICancellationService : IReservationService
{
void Cancel(...);
}
interface IReservation
{
IEnumerable<IReservationService> Services { get; }
}
class Reservation : IReservation
{
private IList<IReservationService> services;
public Reservation(IEnumerable<IReservationService> services)
{
this.services = new List<IReservationService>(services);
}
public IEnumerable Services<IReservationService>
{
get
{
return this.services;
}
}
}