假设我有一个长期建立的存储库,如下所示:
interface IDonutRepository
{
public IEnumerable<Donut> GetDonuts();
}
它已经存在了很长时间,GetDonuts
方法完成了它的说法。然后有一天我需要添加一个显示数据库中所有甜甜圈的新屏幕,结果发现该方法有一个隐藏的功能 - 它会过滤掉所有甜甜圈stale = true
。但是在我的新屏幕上,我想展示所有这些,甚至是陈旧的!这里最好的方法是什么?
假设这个方法在所有地方都被使用,并且默认行为需要保持不变,最好添加一个名为GetAllDonuts
的新方法,该方法不进行过滤,或者我应该只是在onlyFresh
方法上添加GetDonuts
参数?
我猜它只是判断力,但我想知道那里是否有更明智的答案?
答案 0 :(得分:9)
我会重载该方法,创建一个新的重载,该重载采用showStale
参数,然后修改旧方法以使用新的重载传递false
作为参数值。
界面如下:
interface IDonutRepository
{
public IEnumerable<Donut> GetDonuts();
public IEnumerable<Donut> GetDonuts(bool showStale);
}
或者,如果您使用的是.NET 4.0,则可以使用可选参数:
interface IDonutRepository
{
public IEnumerable<Donut> GetDonuts(bool showStale = false);
}
答案 1 :(得分:2)
为什么不使用可选参数?这样您就不会破坏现有代码:
interface IDonutRepository
{
public IEnumerable<Donut> GetDonuts(bool onlyFresh);
}
实现:
public IEnumerable<Donut> GetDonuts(bool onlyFresh = false)
{
if (onlyFresh)
// do stuff
else
// do other stuff
}
答案 2 :(得分:1)
这在某种程度上归结为个人偏好......
如果您能够更改API,我会(个人)重命名当前方法,使其显然不会返回所有Donut
个实例。我的期望是存储库的GetDonuts
方法将获得所有的甜甜圈。这可以通过参数或不同的名称来自行决定。
话虽如此,如果保持兼容性至关重要,那么采用额外参数的方法过载可能是向前发展的最佳选择。 (这很大程度上取决于使用此API的人和位置......)
答案 3 :(得分:1)
根据环境的不同,人们可能会考虑引入一个用于访问甜甜圈的财产。
interface IDonutRepository
{
IEnumerable<Donut> Donuts { get; }
.. or ..
IQueryable<Donut> Donuts { get; }
}
如果您正在使用像Entity Framework或NHibernate这样的Linq-savvy ORM,那么实现此接口相当容易。
旧的GetDonuts方法可以重命名为GetFreshDonuts(),或者您可以将对它的调用重构为以下格式:
repository.Donuts.Where(x => !x.Stale)
答案 4 :(得分:0)
软件发展趋势之一 设计是分离界面 实现。原则是关于 将模块分成公共和 私人部分,以便你可以改变 没有协调的私人部分 与其他模块。但是,有 进一步的区别 - 两者之间的区别 公共和已发布的接口。这个 区别很重要因为它 影响你如何使用 接口