很多派生 类 没有功能性,只针对 "know" 它们的类型
A lot derived classes without functonality only to "know" their type
我觉得下面这个问题有更好的解决办法
假设我们有以下 类 的结构:
class Foo
{
public int Id { get; set; }
}
class Bar1 : Foo
{
}
class Bar2 : Foo
{
}
class Bar3 : Foo
{
}
//.. A lot more of these Foo derivations
派生的 类 没有任何功能。
以下示例说明了 类 的用途:
- 访问 Foo 对象列表中特定类型的特定对象(来自类型 Bar3 且 ID 为 5 的对象)。
- 在 GUI 中显示与 Foo 类型的特定对象相关的不同数据。
有没有更好的方法来识别这些对象之一而不派生它们?
谢谢!
最好改用枚举。
class Foo
{
public int Id { get; set; }
public FooKind Kind { get; set; }
}
子 class 应该增强父 class 的功能。
如果它们在语义上相同并且对派生词没有意义,您可以创建一个Enum
:
public enum SomeGreatEnum
{
Bar1,
Bar2,
Bar3
}
并在Foo
中添加一个属性:
class Foo
{
public SomeGreatEnum SomeGreatEnum { get; set; }
public int Id { get; set; }
}
现在您可以:
过滤器:
foos.Where(x => x.SomeGreatEnum == SomeGreatEnum.Bar1);
根据枚举类型绑定到 GUI。
我认为这感觉像个问题的原因是您的代码的其他部分不是很面向对象。
让我解释一下。让我们假设您使用枚举选项。然后,每当你想用 Foo 做一些事情时,对于每种 Foo 来说都是不同的,你将需要使用 switch 语句,或者通过其他方法 select 集合中的部分项目(比如.Where 在枚举示例中调用)。随着代码的发展,您将拥有如此多的此类语句,以至于开始感觉不对。 Foo 上的每个不同动作都需要处理各种 Foos。此外,每当您对代码的这些部分进行更改时,您都必须确保正确地将它们分开,这意味着您需要立即了解各种 Foo 行为背后的逻辑。
如果有 任何 逻辑变得更复杂的机会,我建议使用接口和许多 类 方法而不是枚举方法。
现在,目前在您的代码中,您可能正在管理 Foos 之外的行为差异。为了使其更面向对象,您可能希望让 Foos 自己管理这种差异。
您可以使用访问者模式:
class Visitor
{
public void Visit(Bar1 foo)
{
Console.WriteLine("Bar1 ID:" + foo.Id);
}
public void Visit(Bar2 foo)
{
Console.WriteLine("Bar2 ID:" + foo.Id);
}
public void Visit(Bar3 foo)
{
Console.WriteLine("Bar3 ID:" + foo.Id);
}
}
我稍微修改了你的 classes:
abstract class Foo
{
public int Id { get; set; }
public abstract void Accept(Visitor visitor);
}
class Bar1 : Foo
{
public override void Accept(Visitor visitor)
{
visitor.Visit(this);
}
}
class Bar2 : Foo
{
public override void Accept(Visitor visitor)
{
visitor.Visit(this);
}
}
class Bar3 : Foo
{
public override void Accept(Visitor visitor)
{
visitor.Visit(this);
}
}
现在让一切正常进行:
var visitor = new Visitor();
var lst = new List<Foo>
{
new Bar1() { Id = 1 },
new Bar2() { Id = 2 },
new Bar3() { Id = 3 }
};
foreach(var element in lst)
{
element.Accept(visitor);
}
/* Output is:
*
* Bar1 ID:1
* Bar2 ID:2
* Bar3 ID:3
*/
完整的设计模式要求 Visitor
实现一个接口,该接口将用于 Accept
方法的签名。
您可以找到有关访问者设计模式的更多信息here and an example of it being used in the .Net framework here。
使用这种设计模式的主要缺点是它在访问者和被访问的具体元素之间创建了耦合。
例如,当添加一个新的 class Bar4 : Foo
时,它需要重写 Accept
方法并且 Visitor
也需要更新一个新的Visit
方法重载。
我觉得下面这个问题有更好的解决办法
假设我们有以下 类 的结构:
class Foo
{
public int Id { get; set; }
}
class Bar1 : Foo
{
}
class Bar2 : Foo
{
}
class Bar3 : Foo
{
}
//.. A lot more of these Foo derivations
派生的 类 没有任何功能。 以下示例说明了 类 的用途:
- 访问 Foo 对象列表中特定类型的特定对象(来自类型 Bar3 且 ID 为 5 的对象)。
- 在 GUI 中显示与 Foo 类型的特定对象相关的不同数据。
有没有更好的方法来识别这些对象之一而不派生它们?
谢谢!
最好改用枚举。
class Foo
{
public int Id { get; set; }
public FooKind Kind { get; set; }
}
子 class 应该增强父 class 的功能。
如果它们在语义上相同并且对派生词没有意义,您可以创建一个Enum
:
public enum SomeGreatEnum
{
Bar1,
Bar2,
Bar3
}
并在Foo
中添加一个属性:
class Foo
{
public SomeGreatEnum SomeGreatEnum { get; set; }
public int Id { get; set; }
}
现在您可以:
过滤器:
foos.Where(x => x.SomeGreatEnum == SomeGreatEnum.Bar1);
根据枚举类型绑定到 GUI。
我认为这感觉像个问题的原因是您的代码的其他部分不是很面向对象。
让我解释一下。让我们假设您使用枚举选项。然后,每当你想用 Foo 做一些事情时,对于每种 Foo 来说都是不同的,你将需要使用 switch 语句,或者通过其他方法 select 集合中的部分项目(比如.Where 在枚举示例中调用)。随着代码的发展,您将拥有如此多的此类语句,以至于开始感觉不对。 Foo 上的每个不同动作都需要处理各种 Foos。此外,每当您对代码的这些部分进行更改时,您都必须确保正确地将它们分开,这意味着您需要立即了解各种 Foo 行为背后的逻辑。
如果有 任何 逻辑变得更复杂的机会,我建议使用接口和许多 类 方法而不是枚举方法。
现在,目前在您的代码中,您可能正在管理 Foos 之外的行为差异。为了使其更面向对象,您可能希望让 Foos 自己管理这种差异。
您可以使用访问者模式:
class Visitor
{
public void Visit(Bar1 foo)
{
Console.WriteLine("Bar1 ID:" + foo.Id);
}
public void Visit(Bar2 foo)
{
Console.WriteLine("Bar2 ID:" + foo.Id);
}
public void Visit(Bar3 foo)
{
Console.WriteLine("Bar3 ID:" + foo.Id);
}
}
我稍微修改了你的 classes:
abstract class Foo
{
public int Id { get; set; }
public abstract void Accept(Visitor visitor);
}
class Bar1 : Foo
{
public override void Accept(Visitor visitor)
{
visitor.Visit(this);
}
}
class Bar2 : Foo
{
public override void Accept(Visitor visitor)
{
visitor.Visit(this);
}
}
class Bar3 : Foo
{
public override void Accept(Visitor visitor)
{
visitor.Visit(this);
}
}
现在让一切正常进行:
var visitor = new Visitor();
var lst = new List<Foo>
{
new Bar1() { Id = 1 },
new Bar2() { Id = 2 },
new Bar3() { Id = 3 }
};
foreach(var element in lst)
{
element.Accept(visitor);
}
/* Output is:
*
* Bar1 ID:1
* Bar2 ID:2
* Bar3 ID:3
*/
完整的设计模式要求 Visitor
实现一个接口,该接口将用于 Accept
方法的签名。
您可以找到有关访问者设计模式的更多信息here and an example of it being used in the .Net framework here。
使用这种设计模式的主要缺点是它在访问者和被访问的具体元素之间创建了耦合。
例如,当添加一个新的 class Bar4 : Foo
时,它需要重写 Accept
方法并且 Visitor
也需要更新一个新的Visit
方法重载。