我已经做了一些搜索(也许我没有充分描述我的问题)但是却找不到答案
假设你有以下POCO:
public class StandardObject
{
public string A {get;set;}
public string B {get;set;}
}
程序中的其他地方有一些处理StandardObjects的逻辑。 存在有时可能需要以不同方式处理StandardObject的情况。我们在创建StandardObject时知道这一点,但是当前属性都不能用于确定链中的这一点。一种方法是在StandardObject上添加和设置标志或类型枚举,并在处理对象时检查它。 E.G。
if(standardObject.IsSpecial){...}
if(standardObject.ObjectType == StandardObjectTypeEnum.Special){...}
这似乎不是最好的方法。
另一种选择是创建派生类:
public class SpecialObject : StandardObject { }
现在我们可以检查类型,而不是检查属性。 E.G。
if(standardObject.GetType() == typeof(SpecialObject)){...}
(取决于我们正在做什么,类型检查可能会以不同的方式实现)
请注意,SpecialObject不会以任何方式添加或更改StandardObject。它本质上是同一个对象。这种方法的优点是更灵活(E.G.我们可以为SpecialObject添加一些额外的属性),但实际上它不会改变。它永远是完全相同的。
对我而言,继承似乎是更好的方法。类型标志看起来像代码气味,前进继承看起来更像是正确的OOP方法。我不确定的是,鉴于StandardObject和SpecialObject是相同的,这样做是不好的做法?或者有什么理由可以避免这种情况吗?
这里有一个类似的问题:
Chess piece hierarchy design: inheritance vs type fields
然而,大多数讨论似乎都集中在国际象棋问题而不是被认为是好的设计
编辑:
封装似乎是流行的解决方案。我避免封装的原因最好在下面的例子中描述:
鉴于“特殊”情况的附加逻辑只需要处理StandardObject的许多不同机制中的一种,其逻辑似乎不属于StandardObject附近的任何地方
答案 0 :(得分:3)
他们两个代码气味。如果您必须在两个相关类型之间以不同方式完成特殊处理,请让它们都实现一些虚拟方法或接口操作,以允许它们处理特殊情况(如果没有必要,则不执行)。
答案 1 :(得分:1)
您还可以使用策略模式封装您的“处理”逻辑,方法是使用抽象基类,您也可以在其中放置共享实现。或者您也可以调用派生实现和继承的实现。
public abstract class Vehicle
{
private MovementStrategy movementStrategy;
protected Vehicle(MovementStrategy strategy)
{
this.movementStrategy = strategy;
}
public void Move()
{
movementStrategy.Move();
}
public virtual void CommonAlert()
{
Console.WriteLine("Base generic vehicle alert");
}
}
public class Car : Vehicle
{
public Car(MovementStrategy movementStrategy)
: base(movementStrategy)
{
}
public override void CommonAlert()
{
Console.WriteLine("Car says 'Honk!'");
}
}
public class Elevator : Vehicle
{
public Elevator(MovementStrategy movementStrategy)
: base(movementStrategy)
{
}
public override void CommonAlert()
{
Console.WriteLine("Elevator says 'Ding!'");
base.CommonAlert();
}
}
public abstract class MovementStrategy
{
public abstract void Move();
}
public class CarMovementStrategy : MovementStrategy
{
public override void Move()
{
Console.WriteLine("Car moved");
}
}
public class ElevatorMovementStrategy : MovementStrategy
{
public override void Move()
{
Console.WriteLine("Elevator moved");
}
}
然后,对于您的主程序,使用示例:
class Program
{
static void Main(string[] args)
{
Vehicle elevator = new Elevator(new ElevatorMovementStrategy());
Vehicle car = new Car(new CarMovementStrategy());
elevator.Move();
car.Move();
elevator.CommonAlert();
car.CommonAlert();
Console.Read();
}
}
答案 2 :(得分:0)
如果您需要根据对象的属性以不同方式处理对象,最好将该方法用于操作类内部的对象。对象的行为可以由某个私有状态变量或派生对象的类型确定,但调用代码不需要知道。
要草拟这一点,说我们有一个元素需要根据某些属性以特定的方式绘制。
如果班级只需要处理,你就必须这样做:
MyElement.Draw();
而不是:
if(MyElement.Flag)
{
DrawBlue(MyElement);
}
else
{
DrawRed(MyElement);
}
对于调用代码,不需要公开必须确定特定行为的方式。