我第一次使用这种模式,并使用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”。
感谢。
答案 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语句中添加任何条目,那么您只需在一个地方执行此操作。