English 中文(简体)
战略模式-正确实施
原标题:Strategy Pattern- Correct Implementation

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

I just wanted to check that this is the correct implementation.
I have a button on a Winform, and when clicked on that will output some data in a particular format, defined by choosing from a drop down box. Now this may change in the future, hence me using the Strategy pattern to encapsulate what changes.

我有一个策略接口,它只公开了一个方法:“DisplayData()”。

单击按钮时,我使用以下代码:

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。

谢谢

最佳回答

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

例如。

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();
}

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

问题回答

首先,您可以移动viewData.DisplayData()离开开关。无需针对每种情况重复。能够以相同的方式调用DisplayData,这就是您最初引入该接口的全部意义。

在每个情况中以相同的方式传递参数看起来也有点重复。因此,也许可以使用Dictionary<;字符串,函数<;操作、研究、IViewData>>。但是,如果不同的类需要不同的构造函数,这是行不通的。

您应该将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语句中添加任何条目,则只需在一个位置执行即可。





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...