switch/case 关于控制器中的视图模型,有任何重构建议吗?
switch/case on viewmodel in controller, any refactoring advice?
我可以使用一些关于重构的建议。在我的应用程序中,用户可以动态添加新的表单字段;自定义字段。对于每种类型(文本、下拉列表、复选框等),都定义了一个 ViewModel(TextBoxViewModel、DropDownViewModel、CheckboxViewModel 等)。
当我 post 表单时,会执行适当的编辑操作,我会读取每个自定义字段以存储它们的值。
目前实现有效但很丑;我 switch/case/if/else 通过所有 ViewModel 类型并根据类型执行所需的逻辑。
这是当前的实现:
private static void MapToModel(Ticket ticket, TicketViewModel model)
{
ticket.Id = model.Id;
ticket.Name = model.Name;
ticket.Attributes.Clear();
foreach (var cvm in model.Controls)
{
var attribute = new TicketAttribute
{
Id = cvm.Id,
Name = cvm.Name,
};
if (cvm is TextBoxViewModel)
{
attribute.Value = ((TextBoxViewModel) cvm).Value;
}else if (cvm is DropDownListViewModel)
{
attribute.Value = ((DropDownListViewModel)cvm).Values;
}
ticket.Attributes.Add(attribute);
}
}
我想将它重构为类似这样的东西,但不将所有逻辑都放在 ViewModel 中。我能想到的最好的方法是访问者模式,我会在其中向 ViewModel class 添加一个 Accept 方法,并使用访问者来执行所需的逻辑:
这仍然需要 AddAttribute 方法中类型的相同切换逻辑:
foreach (var cvm in model.Controls)
{
ticket.Attributes.AddAttribute(cvm);
}
这需要 ViewModel 中的逻辑class
foreach (var cvm in model.Controls)
{
ticket.Attributes.Add(cvm.AddAttribute);
}
我想重构它以创建更通用的方法,以便将来添加新类型的字段时,我不必使用新结构更新所有代码来检查类型。
[求助后解决]
我不得不转换对象,我不能在 IControlViewModel 的不同实现中使用不同的返回类型,所以这是我必须解决的一部分,但总的来说这很漂亮。
ticket.Attributes = model.Controls
.OfType<IControlViewModel>()
.Select(cvm => new TicketAttribute {
Id = cvm.Id,
Name = cvm.Name,
Value = (string)cvm.OutputValue
})
.ToList();
public interface IControlViewModel
{
string Id { get; }
string Name { get; }
object OutputValue { get; }
}
public abstract class ControlViewModel : IControlViewModel
{
public string Id { get; set; }
public abstract string Type { get; }
public string Label { get; set; }
public string Name { get; set; }
public bool Visible { get; set; }
public abstract object OutputValue { get; }
}
public class TextBoxViewModel : ControlViewModel
{
public override string Type
{
get { return "textbox"; }
}
public override object OutputValue
{
get
{
return Value;
}
}
public string Value {set; }
}
1) 创建一个接口,定义您将在每个视图模型
上具有输出值 属性
public interface IControlViewModel
{
object OutputValue{get;}
}
2) 在每个视图模型中实现接口:
public TextBoxViewModel: IControlViewModel
{
...
public object OutputValue
{
get
{
//return whatever is your expected output value from control
return Value;
}
}
...
}
3) 然后你可以用这条 LINQ 语句获取所有属性:
ticket.Attributes = model.Controls
.OfType<IControlViewModel>()
.Select(cvm => new TicketAttribute {
Id = cvm.Id,
Name = cvm.Name,
Value = cvm.OutputValue
})
.ToList();
4) 即使您创建新的控件类型,此代码也能正常工作,只需确保在新的视图模型中实现接口即可。
我可以使用一些关于重构的建议。在我的应用程序中,用户可以动态添加新的表单字段;自定义字段。对于每种类型(文本、下拉列表、复选框等),都定义了一个 ViewModel(TextBoxViewModel、DropDownViewModel、CheckboxViewModel 等)。
当我 post 表单时,会执行适当的编辑操作,我会读取每个自定义字段以存储它们的值。
目前实现有效但很丑;我 switch/case/if/else 通过所有 ViewModel 类型并根据类型执行所需的逻辑。
这是当前的实现:
private static void MapToModel(Ticket ticket, TicketViewModel model)
{
ticket.Id = model.Id;
ticket.Name = model.Name;
ticket.Attributes.Clear();
foreach (var cvm in model.Controls)
{
var attribute = new TicketAttribute
{
Id = cvm.Id,
Name = cvm.Name,
};
if (cvm is TextBoxViewModel)
{
attribute.Value = ((TextBoxViewModel) cvm).Value;
}else if (cvm is DropDownListViewModel)
{
attribute.Value = ((DropDownListViewModel)cvm).Values;
}
ticket.Attributes.Add(attribute);
}
}
我想将它重构为类似这样的东西,但不将所有逻辑都放在 ViewModel 中。我能想到的最好的方法是访问者模式,我会在其中向 ViewModel class 添加一个 Accept 方法,并使用访问者来执行所需的逻辑:
这仍然需要 AddAttribute 方法中类型的相同切换逻辑:
foreach (var cvm in model.Controls)
{
ticket.Attributes.AddAttribute(cvm);
}
这需要 ViewModel 中的逻辑class
foreach (var cvm in model.Controls)
{
ticket.Attributes.Add(cvm.AddAttribute);
}
我想重构它以创建更通用的方法,以便将来添加新类型的字段时,我不必使用新结构更新所有代码来检查类型。
[求助后解决]
我不得不转换对象,我不能在 IControlViewModel 的不同实现中使用不同的返回类型,所以这是我必须解决的一部分,但总的来说这很漂亮。
ticket.Attributes = model.Controls
.OfType<IControlViewModel>()
.Select(cvm => new TicketAttribute {
Id = cvm.Id,
Name = cvm.Name,
Value = (string)cvm.OutputValue
})
.ToList();
public interface IControlViewModel
{
string Id { get; }
string Name { get; }
object OutputValue { get; }
}
public abstract class ControlViewModel : IControlViewModel
{
public string Id { get; set; }
public abstract string Type { get; }
public string Label { get; set; }
public string Name { get; set; }
public bool Visible { get; set; }
public abstract object OutputValue { get; }
}
public class TextBoxViewModel : ControlViewModel
{
public override string Type
{
get { return "textbox"; }
}
public override object OutputValue
{
get
{
return Value;
}
}
public string Value {set; }
}
1) 创建一个接口,定义您将在每个视图模型
上具有输出值 属性public interface IControlViewModel
{
object OutputValue{get;}
}
2) 在每个视图模型中实现接口:
public TextBoxViewModel: IControlViewModel
{
...
public object OutputValue
{
get
{
//return whatever is your expected output value from control
return Value;
}
}
...
}
3) 然后你可以用这条 LINQ 语句获取所有属性:
ticket.Attributes = model.Controls
.OfType<IControlViewModel>()
.Select(cvm => new TicketAttribute {
Id = cvm.Id,
Name = cvm.Name,
Value = cvm.OutputValue
})
.ToList();
4) 即使您创建新的控件类型,此代码也能正常工作,只需确保在新的视图模型中实现接口即可。