我想引用之前在SO上使用的例子,涉及鸭子和电子鸭子:
作者提出的一种解决方案是将逻辑放在电鸭的游泳方法中,以便使其自行启动:
public interface IDuck
{
void Swim();
}
public class Duck : IDuck
{
public void Swim()
{
//do something to swim
}
}
public class ElectricDuck : IDuck
{
public void Swim()
{
if (!IsTurnedOn)
return;
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
}
违反LSP的原始方式如下:
void MakeDuckSwim(IDuck duck)
{
if (duck is ElectricDuck)
((ElectricDuck)duck).TurnOn();
duck.Swim();
}
作者提出的一种解决方案是将逻辑放在电鸭的游泳方法中,以便使其自行启动:
public class ElectricDuck : IDuck
{
public void Swim()
{
if (!IsTurnedOn)
TurnOn();
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
}
我曾遇到其他情况,可以创建一个扩展接口来支持某种初始化:
public interface IInitializeRequired
{
public void Init();
}
Electric Duck可以通过这个接口进行扩展:
public class ElectricDuck : IDuck, IInitializeRequired
{
public void Swim()
{
if (!IsTurnedOn)
return;
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
#region IInitializeRequired Members
public void Init()
{
TurnOn();
}
#endregion
}
编辑:扩展接口的原因是基于作者说自动在游泳方法中打开可能会产生其他不希望的结果。
那么,该方法不再检查和转换为特定类型,而是可以寻找扩展接口:
void MakeDuckSwim2(IDuck duck)
{
var init = duck as IInitializeRequired;
if (init != null)
{
init.Init();
}
duck.Swim();
}
我提出了将初始化概念抽象化并创建一个名为IElectricDuck的扩展接口,其中包含TurnOn()方法,这样做似乎是正确的。然而,整个初始化概念可能只是因为电动鸭而存在。
这是否是更好的解决方案,还是它只是LSP违规的伪装。
谢谢。
IDuck.HasEnergy
等,然后您可以强制执行“获取能量”,这在原则上对于每只鸭子都是相同的,但在细节上却有所不同(一只可能吃东西,另一只可能插入电池或打开开关)。 - Grant Thomas