【问题标题】:Identify implementations of base class in an array识别数组中基类的实现
【发布时间】:2013-03-07 14:51:23
【问题描述】:

我有以下问题:我有一组自动(监听事件)控制我的模型的引擎。下图显示了一般的类图:

现在我有一个知道 EngineFacade 的客户端,我想从客户端从 Engine2 设置属性 Active,但是客户端和 EngineFacade 都不知道三个引擎中的哪一个是 Engine2。

有两种方法,但我不喜欢其中任何一种:

  1. 检查其中一个引擎是否属于 Engine2 类型 - 如果有另一个执行相同任务但名称不同的类,我必须在 EngineBuilder 和 EngineFacade 中更改它。
  2. 检查标识符字符串 - 我不太喜欢魔术字符串。

我在客户网站上所知道的是存在或应该有一个处理网格的引擎。但我不知道更多。

也许我必须在两个恶魔之间做出选择,但也许你们中的一个有更好的解决方案。

【问题讨论】:

  • 如果你必须分别识别每个引擎,简单的选择是给它一个唯一的标识符。另一种方法是在基础引擎上有一个 name 属性。每个引擎都实现 name 属性,然后触发一个事件,然后检查 sender 参数。
  • 也许你应该检查一下门面提供的抽象。听起来你有一些泄漏。
  • 您可能希望在图表中包含客户端、其方法和变量,或者发布一些说明用法的代码。
  • 如果 Engine2 比 Engine1 和 Engine 3 更专业,那么事实上它正在实现一个额外的服务契约 ISpecificToEngine2。明确定义和公开此附加服务合同将允许客户选择所有实现此附加合同的引擎。
  • @Yggdrasil:您的抽象模型不再准确反映您的业务需求。如果这是一个孤立的案例,请忍受它;但如果它只是即将到来的冰山一角,请在它沉没之前立即解决它。

标签: c# design-patterns casting magic-string


【解决方案1】:

你可以在Engine2的实现上使用一个属性,像这样:

[AttributeUsage(AttributeTargets.Class)]
public class HandlesGridAttribute : Attribute { }

然后将其应用于派生:

[HandlesGrid]
public Engine2 : EngineBase { ... }

然后,在您的客户端中,检查属性:

IEnumerable<EngineBase> bases = ...;

// Get all the implementations which handle the grid.
IEnumerable<EngineBase> handlesGrid = bases.
    Where(b => b.GetType().
        GetCustomAttributes(typeof(HandlesGridAttribute), true).Any());

// Set the active property.
foreach (EngineBase b in handlesGrid) b.Active = true;

这里的主要缺点(可能适用于您也可能不适用于您)是您无法在运行时更改值(因为该属性是在编译时烘焙的)。如果您的引擎以这种方式不是动态的,那么属性是正确的方法。

如果您需要更改派生是否可以在运行时执行此操作,那么您必须退回到您的第二个选项,即识别引擎属性的代码构造。请注意,它不一定是字符串(我也不喜欢这样),但它可以是更有条理的东西,可以为您提供所需的信息。

【讨论】:

  • 谢谢,这就是我要找的。我只需要检查它的性能如何。
  • 好像没那么贵。以防万一我在我使用它的地方缓存这个引擎。
猜你喜欢
  • 2014-06-03
  • 2012-09-22
  • 2014-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-15
  • 1970-01-01
  • 2012-10-25
相关资源
最近更新 更多