2

我一次又一次地得到沿这些行的代码,在那里我创建一些对象,然后循环它们以使用另一个类初始化一些属性......

ThingRepository thingRepos      = new ThingRepository();
GizmoProcessor  gizmoProcessor  = new GizmoProcessor();
WidgetProcessor widgetProcessor = new WidgetProcessor();

public List<Thing> GetThings(DateTime date)
{
    List<Thing> allThings = thingRepos.FetchThings();

    // Loops through setting thing.Gizmo to a new Gizmo
    gizmoProcessor.AddGizmosToThings(allThings);

    // Loops through setting thing.Widget to a new Widget
    widgetProcessor.AddWidgetsToThings(allThings);

    return allThings;
}

...这只是,嗯,感觉不对。

  1. 这是一个坏主意吗?
  2. 是否有我在这里使用的反模式的名称?
  3. 有哪些替代方案?


编辑:假设两者都GizmoProcessor必须WidgetProcessor进行一些计算,并从其他表中获取一些额外的数据。它们不仅仅是存储在存储库中的数据。他们正在基于每个创建新的 Gizmo 和小部件Thing,并将它们分配给Thing的属性。

这让我觉得奇怪的原因是它Thing不是一个自主的对象。它不能创建自己和子对象。它需要更高级别的代码来创建一个完全完成的对象。我不确定这是否是一件坏事!

4

4 回答 4

1

ThingRepository应该是获取Thing's 集合的单一访问点,或者至少这是开发人员直观地查看的地方。因此,GetThings(DateTime date)应该由另一个对象提供感觉很奇怪。我宁愿把这个方法放在ThingRepository自己身上。

事实上,Thing返回的 'sGetThings(DateTime date)是不同的,比返回的那些“更胖”的动物ThingRepository.FetchThings()也让人感到尴尬和违反直觉。如果Gizmo并且Widget确实是Thing实体的一部分,那么您应该能够在每次拥有 的实例时访问它们Thing,而不仅仅是GetThings(DateTime date).

如果 Date 参数 inGetThings()不重要或可以在其他时间收集,我将使用计算属性 on来实现对andThing的按需访问:GizmoWidget

public class Thing
{
  //...

  public Gizmo Gizmo
  {
    get 
    { 
       // calculations here 
    }
  }

  public Widget Widget
  {
    get 
    { 
       // calculations here 
    }
  }
}

请注意,只要执行的计算成本不太高,这种方法就有效。不建议使用昂贵处理的计算属性 - 请参阅http://msdn.microsoft.com/en-us/library/bzwdh01d%28VS.71%29.aspx#cpconpropertyusageguidelinesanchor1

然而,这些计算不必在 getter 中内联实现——它们可以委托给第三方 Gizmo/Widget 处理器,可能带有缓存策略等。

于 2013-01-15T10:23:08.350 回答
0

唯一真正的潜在问题是您多次迭代同一个循环,但如果您需要访问数据库以获取所有小工具和小部件,那么批量请求它们可能会更有效,因此传递完整列表添加到您的 Add... 方法将是有意义的。

另一种选择是考虑在第一个存储库调用中返回 gizmo 和小部件(假设它们位于同一个存储库中)。它可能会使查询更复杂,但它可能会更有效。当然,除非你在取东西时并不总是需要获取小工具和小部件。

于 2013-01-15T00:47:43.117 回答
0

如果您有复杂的初始化,那么您可以使用策略模式。这是改编自此策略模式概述​​的快速概述

创建一个策略接口来抽象初始化

public interface IThingInitializationStrategy
{
  void Initialize(Thing thing);
} 

策略可以使用的初始化实现

public class GizmosInitialization
{
  public void Initialize(Thing thing)
  {
     // Add gizmos here and other initialization
  }
}

public class WidgetsInitialization
{
  public void Initialize(Thing thing)
  {
    // Add widgets here and other initialization
  }
}

最后是一个以抽象方式接受策略实现的服务类

internal class ThingInitalizationService
{
  private readonly IThingInitializationStrategy _initStrategy;

  public ThingInitalizationService(IThingInitializationStrategy initStrategy)
  {
     _initStrategy = initStrategy;
  }

  public Initialize(Thing thing)
  {
    _initStrategy.Initialize(thing);
  }
}

然后您可以像这样使用初始化策略

var initializationStrategy = new GizmosInitializtion();
var initializationService = new ThingInitalizationService(initializationStrategy);


List<Thing> allThings = thingRepos.FetchThings();

allThings.Foreach ( thing => initializationService.Initialize(thing) );
于 2013-01-15T12:32:36.837 回答
0

要回答您的问题:

  1. 这是一个坏主意吗?

    • 根据我的经验,在你需要改变它之前,你很少知道这是一个好主意还是坏主意。
    • IMO,代码是:过度设计、设计不足不可读
    • 同时,您尽最大努力并坚持最佳实践(KISS、单一责任等)
    • 就个人而言,我认为处理器类不应该修改任何事物的状态。
    • 我也不认为应该给处理器类一个要修改的东西的集合。
  2. 是否有我在这里使用的反模式的名称?

    • 抱歉,帮不上忙。
  3. 有哪些替代方案?

就个人而言,我会这样编写代码:

public List<Thing> GetThings(DateTime date)
{
    List<Thing> allThings = thingRepos.FetchThings();

    // Build the gizmo and widget for each thing
    foreach (var thing in allThings)
    {
        thing.Gizmo = gizmoProcessor.BuildGizmo(thing);
        thing.Widget = widgetProcessor.BuildWidget(thing);
    }

    return allThings;
}

我的理由是:

  1. 该代码位于“获取事物”的类中。所以从逻辑上讲,我认为遍历每个 Thing 对象并初始化它们是可以接受的。
  2. 意图很明确:我Thing在返回它们之前初始化每个属性。
  3. Thing我更喜欢在中心位置初始化 的任何属性。
  4. 我认为 gizmoProcessor 和 widgetProcessor 类不应该与 Collection of Things 有任何关系
  5. 我更喜欢处理器有一种方法来构建和返回单个小部件/gizmo

但是,如果您的处理器类一次构建多个属性,那么我只会重构每个处理器的属性初始化。

public List<Thing> GetThings(DateTime date)
{
    List<Thing> allThings = thingRepos.FetchThings();

    // Build the gizmo and widget for each thing
    foreach (var thing in allThings)
    {
        // [Edited]
        // Notice a trend here: The common Initialize(Thing) interface
        // Could probably be refactored into some 
        // super-mega-complex Composite Builder-esque class should you ever want to
        gizmoProcessor.Initialize(thing);
        widgetProcessor.Initialize(thing);
    }

    return allThings;
}

附言:

  • 我个人不太关心(反)模式名称。
  • 虽然它有助于在更高的抽象级别讨论问题,但我不会将每个(反)模式名称都提交给记忆。
  • 当我遇到一个我认为有用的模式时,我只会记住它。
  • 我很懒惰,我的理由是:如果我只使用少数,为什么还要记住每个模式和反模式?

[编辑]

注意到已经给出了关于使用策略服务的答案。

于 2013-01-16T11:01:35.477 回答