战略模式 - 正确实施

时间:2011-02-14 12:46:04

标签: c# strategy-pattern

我第一次使用这种模式,并使用C#。

我只想检查这是否是正确的实施方案 我在Winform上有一个按钮,当点击它时会输出一些特定格式的数据,通过从下拉框中选择来定义。现在这可能会在未来发生变化,因此我使用策略模式来封装变化。

我有一个“策略界面”,它只是暴露了一种方法:“显示数据()”。

点击我的按钮,我使用以下代码:

private void ConfirmButton_Click(object sender, EventArgs e)
    {
        IViewData viewData;

        switch (outputMedia)
        {
            case "Excel":
                viewData = new ExcelOutput(operation, study);
                viewData.DisplayData();
                break;
            case "Spotfire":
                viewData = new SpotfireOutput(operation, study);
                viewData.DisplayData();
                break;
        }


    }

这是否是使用此模式的可接受方式?显然,如果识别出额外的输出媒体,那么我将简单地创建一个新的子类并在switch语句中添加一个额外的“case”。

感谢。

3 个答案:

答案 0 :(得分:4)

使用策略的正确方法是将IViewData对象的创建与其使用分开。创建本身可能由工厂方法处理。然后你可以在一个单独的位置使用创建的IViewData,它完全不知道对象的具体类。

E.g。

private IViewData CreateViewData()
{
    IViewData viewData;

    switch (outputMedia)
    {
        case "Excel":
            viewData = new ExcelOutput(operation, study);
            break;
        case "Spotfire":
            viewData = new SpotfireOutput(operation, study);
            break;
    }
    return viewData;
}

...

private void ConfirmButton_Click(object sender, EventArgs e)
{
    IViewData viewData = CreateViewData();

    viewData.DisplayData();
}

现在,通过重构工厂方法,您可以进一步改进解决方案。您可以决定使用Dictionary而不是switch,或者只创建一次视图数据对象并缓存它们,或者(如您所建议的)用依赖注入替换它...

答案 1 :(得分:2)

首先,您可以将viewData.DisplayData();移出开关。无需为每种情况重复一遍。并且能够以相同的方式为所有这些调用DisplayData是你首先介绍该接口的全部要点。

在每个case中以相同的方式传递参数看起来也有点重复。所以也许使用Dictionary<string,Func<Operation,Study,IViewData>>代替。但是如果不同的类需要不同的构造函数,那么这将不起作用。

答案 2 :(得分:1)

您应该将switch语句移动到自己的方法中,理想情况是在某些控制器类上。这意味着当您需要IViewData对象时,不必再次重新编写开关代码。

private void ConfirmButton_Click(object sender, EventArgs e)
{
    IViewData viewData = ViewDataController.GetViewDataController(outputMedia, operation, study);

   viewData.DisplayData();

}

然后在你的控制器中:

 public class ViewDataController
 {
    public static IViewData GetViewDataController(string outputMedia, string operation, string study)
    {
      IViewData viewData = null;

      switch (outputMedia)
      {
        case "Excel":
            viewData = new ExcelOutput(operation, study);
            break;
        case "Spotfire":
            viewData = new SpotfireOutput(operation, study);
            break;
      }
      return viewData;
     }

这将允许您在整个应用程序中重用相同的代码,如果您需要在switch语句中添加任何条目,那么您只需在一个地方执行此操作。