基于工厂模式在ASP.NET MVC中动态生成表单控件的技术问询
基于工厂模式实现MVC表单视图生成方案
核心结论
必须为LongAnswerText和MultipleChoice分别创建对应的ConcreteStrategy类,这是实现类型与渲染逻辑解耦、可扩展的关键。
实现思路拆解
1. 定义统一的策略接口
先创建一个IPollingQuestionRenderer接口,规定所有问题类型必须实现的渲染方法:
public interface IPollingQuestionRenderer { HtmlString Render(MeetingPollingQuestion question); }
2. 实现两种类型的ConcreteStrategy类
分别针对两种问题类型编写控件渲染逻辑:
- LongAnswerTextRenderer(对应标签+文本框)
public class LongAnswerTextRenderer : IPollingQuestionRenderer { public HtmlString Render(MeetingPollingQuestion question) { var container = new TagBuilder("div"); // 生成问题标签 var label = new TagBuilder("label"); label.Attributes["for"] = $"Q_{question.Id}"; label.InnerHtml.Append(question.Title); container.InnerHtml.AppendHtml(label); // 生成文本框 var textBox = new TagBuilder("textarea"); textBox.Attributes["id"] = $"Q_{question.Id}"; textBox.Attributes["name"] = $"PollAnswers[{question.Id}]"; textBox.Attributes["rows"] = "5"; container.InnerHtml.AppendHtml(textBox); return new HtmlString(container.ToString()); } }
- MultipleChoiceRenderer(对应标签+单选按钮组)
public class MultipleChoiceRenderer : IPollingQuestionRenderer { public HtmlString Render(MeetingPollingQuestion question) { var container = new TagBuilder("div"); // 生成问题标签 var label = new TagBuilder("label"); label.InnerHtml.Append(question.Title); container.InnerHtml.AppendHtml(label); // 生成单选按钮组 var options = question.PartsValues.Cast<ChoiceOption>(); foreach (var option in options) { var optionContainer = new TagBuilder("div"); var radioBtn = new TagBuilder("input"); radioBtn.Attributes["type"] = "radio"; radioBtn.Attributes["id"] = $"Q_{question.Id}_Opt_{option.Id}"; radioBtn.Attributes["name"] = $"PollAnswers[{question.Id}]"; radioBtn.Attributes["value"] = option.Value; optionContainer.InnerHtml.AppendHtml(radioBtn); var optionLabel = new TagBuilder("label"); optionLabel.Attributes["for"] = $"Q_{question.Id}_Opt_{option.Id}"; optionLabel.InnerHtml.Append(option.Text); optionContainer.InnerHtml.AppendHtml(optionLabel); container.InnerHtml.AppendHtml(optionContainer); } return new HtmlString(container.ToString()); } }
3. 实现工厂类封装类型判断
创建PollingRendererFactory,根据问题类型返回对应渲染器:
public static class PollingRendererFactory { public static IPollingQuestionRenderer GetRenderer(MeetingPollingQuestionType type) { return type switch { MeetingPollingQuestionType.LongAnswerText => new LongAnswerTextRenderer(), MeetingPollingQuestionType.MultipleChoice => new MultipleChoiceRenderer(), _ => throw new NotSupportedException($"不支持的问题类型:{type}") }; } }
4. 在MVC视图中调用工厂生成表单
在Razor视图中遍历解析后的JSON数据,通过工厂生成对应控件:
@model List<MeetingPollingQuestion> <form asp-action="SubmitPoll" method="post"> @foreach (var question in Model) { var renderer = PollingRendererFactory.GetRenderer(question.Type); @renderer.Render(question) } <button type="submit">提交问卷</button> </form>
方案优势
- 解耦逻辑:新增问题类型时,只需添加新的Renderer类和工厂分支,无需修改现有代码
- 可维护性:每种类型的渲染逻辑独立,便于调试和修改
- 符合开闭原则:对扩展开放,对修改关闭
注意事项
- 确保JSON解析后的
MeetingPollingQuestion模型包含Id、Title、Type及对应类型的PartsValues(比如多选题的选项列表) - 渲染器中要正确设置表单控件的
name属性,保证MVC模型绑定能正确接收提交的答案
内容的提问来源于stack exchange,提问作者Jefferson
相关产品推荐
相关产品推荐

