我正在设计一个简单的表单创建引擎,用户可以使用各种样板字段类型(日期,文本,DropDown)组合新表单
我决定对域对象(表单字段)进行建模,而不依赖于用于将这些字段呈现给UI的对象。
这是定义域的合同及其某些特化的接口:
namespace Acme.Core.Domain{
public interface IFormField
{
bool Visible { get; set; }
string Key { get; set; }
event EventHandler<FieldVisibilityChangedEventArgs> VisibilityChanged;
FieldType Type{get;}
void Validate(IEnumerable<ValidationError> errors);
int DataId {get;set;}
}
public interface IDropDownField:IFormField{
IDictionary<string, string> Items { get; set; }
KeyValuePair<string, string> SelectedValue { get; set; }
}
public interface IDateField:IFormField{
DateTime? SelectedDate{get;set}
}
}
对于UI方面,我构建了一个并行类型层次结构。这使得与数据验证有关的业务规则的域对象与UI问题分开,即如何呈现给定字段(MVC HtmlHelper vs WebForm WebControl):
namespace Acme.UI{
public interface IControl
{
//parallel to IFormField
bool Visible { get; set; }
string ID { get; set; }
}
public interface IDropListControl:IControl
{
//parallel to IDropDownField
}
public interface IDatePickerControl: IControl
{
//parallel to IDateField
}
public interface IControlFactory {
IControl CreateControl(IFormField field);
}
}
虽然这种设计让我可以自由地独立于UI设计域模型,但我还没有找到一种干净的方式来连接和管理这两个层次结构。我觉得我应该能够利用泛型将并行类相互连接起来,但我不能完全理解它的外观。是否有一种模式可以解决关联问题或者完全不需要并行类层次结构?
编辑:我的UI层引用了我的业务层(Core.csproj)。以下是我将UI类层次结构连接到域类层次结构的几个示例。这些类型目前不使用泛型,但我觉得它们应该是。
// create concrete instances of IControl based on the the domain object passed in
public interface IControlFactory {
IControl CreateControl(IFormField field);
}
// scrape values form the UI controls and apply them to the appropriate domain object
public interface IFormFieldDataBinder{
void Bind(IFormField field, IControl control);
}
答案 0 :(得分:1)
我认为两个层次结构之间的区别是如此之小,你真的应该考虑价值 - 或 - 区别是什么。例如,如果您正在考虑的是具有不同渲染形式的多个下拉列表控件,那么问问自己,如果不是在设计器中,您将在哪里选择具体控件?
也许你的IDropdownListControl
可以是一个带有抽象'Render'方法的基类?
您的IFormField
和IControl
非常相似,我不知道您购买的是什么?
IDropDownField
特别看起来像MVC术语中的模型对象,它是关于实例化表单时字段所保存的数据。它不是关于表单的形状(你说它是一个领域模型)。
是否所有IDropListControls
都支持模型IDropDownField
? (在这种情况下,我真的只需删除IDropDownField
并直接在IDropListControl
上声明属性。
考虑重用抽象原则。对于您创建的每个接口,您能想到两个实现还是它们只是具体的类?