这段代码的MVC版本是什么?

时间:2009-06-07 15:48:31

标签: model-view-controller language-agnostic design-patterns

我正试图围绕如何企业化我的代码:采用一个简单的例程并将其分为3或4个类中的5或6个方法。

我很快就找到了三个简单的代码示例我目前是如何编写的。有人可以将这些转换为MVC / MVP混淆版本吗?


示例1 姓氏是必填项。如果未输入任何内容,则将文本框着色为红色如果输入了东西,请将其涂成绿色:

private void txtLastname_TextChanged(object sender, EventArgs e)
{
   //Lastname mandatory. 
   //Color pinkish if nothing entered. Greenish if entered.
   if (txtLastname.Text.Trim() == "")
   {
      //Lastname is required, color pinkish
      txtLastname.BackColor = ControlBad;
   }
   else
   {
      //Lastname entered, remove the coloring
      txtLastname.BackColor = ControlGood;
   }
}

示例2 名字是可选的,但是尝试来获取它。我们将为此“尝试获取”字段添加蓝色色调:

private void txtFirstname_TextChanged(object sender, EventArgs e)
{
    //Firstname can be blank.
    //Hint them that they should *try* to get it with a bluish color.
    //If they do enter stuff: it better be not all spaces.
    if (txtFirstname.Text == "")
    {
       //Nothing there, hint it blue
       txtFirstname.BackColor = ControlRequired;
    }
    else if (txtFirstname.Text.Trim() == "")
    {
       //They entered spaces - bad user!
       txtFirstname.BackColor = ControlBad;
    }
    else
    {
       //Entered stuff, remove coloring
       txtFirstname.BackColor = SystemColors.Window;
    }
}

示例3 年龄完全是可选的。如果输入年龄 ,则最好有效:

private void txtAge_TextChanged(object sender, EventArgs e)
{
   //Age is optional, but if entered it better be valid
   int nAge = 0;
   if (Int32.TryParse(txtAge.Text, out nAge))
   {
      //Valid integer entered
      if (nAge < 0)
      {
         //Negative age? i don't think so
         txtAge.BackColor = ControlBad;
      }
      else
      {
         //Valid age entered, remove coloring
         txtAge.BackColor = SystemColors.Window;
      }
   }
   else
   {
      //Whatever is in there: it's *not* a valid integer,
      if (txtAge.Text == "")
      {
         //Blank is okay
         txtAge.BackColor = SystemColors.Window;
      }
      else
      {
         //Not a valid age, bad user
         txtAge.BackColor = ControlBad;
      }
   }
}

每当我看到MVC代码时,它看起来几乎就像是将代码随机拆分成不同的方法,类和文件。我无法确定他们疯狂的原因或模式。没有任何理解他们为什么它是某种方式,它没有任何意义。并使用模型视图控制器演示者等词语,就像我应该知道这意味着什么,没有帮助。

  

该模型是您的数据。

     

视图显示屏幕上的数据。

     

控制器用于执行   用户操作

橘子味道好吃。


这是我为了使代码更难以遵循而分裂的尝试。这是否接近MVC?

private void txtFirstname_TextChanged(object sender, EventArgs e)
{
   FirstnameTextChangedHandler(sender, e);
}

private void FirstnameTextChangedHandler(sender, e)
{
   string firstname = GetFirstname();

   Color firstnameTextBoxColor = GetFirstnameTextBoxColor(firstname);

   SetFirstNameTextBoxColor(firstnameTextBoxColor);
}

private string GetFirstname()
{
   return txtFirstname.Text;
}

private Color GetFirstnameTextBoxColor(string firstname)
{
    //Firstname can be blank.
    //Hint them that they should *try* to get it with a bluish color.
    //If they do enter stuff: it better be not all spaces.
    if (firstname == "")
    {
       //Nothing there, hint it blue
       return GetControlRequiredColor();
    }
    else if (firstname.Trim() == "")
    {
       //They entered spaces - bad user!
       return GetControlBadColor();
    }
    else
    {
       //Entered stuff, remove coloring
       return GetControlDefaultColor();
    }
}

private Color GetControlRequiredColor()
{
   return ControlRequired;
}

private Color GetControlBadColor()
{
   return ControlBad;
}

private Color GetControlGoodColor()
{
   return ControlGood;
}
//am i doin it rite

我已经混淆了代码,但它仍然是完全的。我收集的MVC混淆的下一步是将代码隐藏在3或4个不同的文件中。

这是我不明白的下一步。将哪些函数移入其他类的逻辑分离是什么?有人可以将我上面的3个简单例子翻译成完全成熟的MVC混淆吗?


编辑:不是ASP / ASP.NET / Online。假装它在台式机,手持设备,表面,自助服务终端上。并假装它与语言无关。

5 个答案:

答案 0 :(得分:2)

MVC / MVP模式的目的不是混淆,而是separation of concerns。混淆是(conceal the) intended meaning in communication, making communication confusing, intentionally ambiguous, and more difficult to interpretref。模式的使用是为了使代码更清晰,并且更多可以理解。我建议您先阅读MVCMVP上的维基百科条目。

这两种模式都是构建代码的方式,因此您的应用程序可以分解为具有明确定义的交互边界的特定目的的元素。这些问题在各种架构组件中是分开和隔离的,而不是在整个应用程序的各个类中具有专门解决业务问题,输入/输出处理和表示的代码。这些架构元素通过交互边界(接口)彼此隔离,使它们彼此更加独立并且更容易修改而不会影响整个应用程序。

答案 1 :(得分:1)

我在为Windows Forms实现MVC时的主要想法是,我希望对我的模型和控制器进行单元测试。为了实现这一点,我的控制器不应该知道使用它的视图,因此任何应该在UI级别处理的通知都实现为事件。在您的示例中,我的控制器看起来像这样:

class Controller
{
    // This is the model we are operating on
    private Model model_;

    public enum Status
    {
        Normal,
        Required,
        Good,
        Bad
    }

    public delegate void FirstNameStatusChangedDelegate(Status newStatus);
    public event FirstNameStatusChangedDelegate FirstNameStatusChangedEvent;

    public string FirstName
    {
        get { return model_.FirstName; }
        set
        {
            if (value == "")
                RaiseFirstNameStatusChanged(Status.Required);
            else if ( value.Trim() == "" )
                RaiseFirstNameStatusChanged(Status.Bad);
            else
            {
                model_.FirstName = value;
                RaiseFirstNameStatusChanged(Status.Normal);
            }
        }
    }

    private void RaiseFirstNameStatusChanged(Status newStatus)
    {
        if ( FirstNameStatusChangedEvent != null )
            FirstNameStatusChangedEvent(newStatus);
    }
}

该视图将为FirstNameStatusChanged事件提供处理程序:

class View : Form
{
    private Controller controller_;
    private static readonly Dictionary<Controller.Status, Color> statusColors_ = new Dictionary<Controller.Status, Color>
    {
        {Controller.Status.Normal, SystemColors.Window},
        {Controller.Status.Required, ControlRequired},
        {Controller.Status.Good, ControlGood},
        {Controller.Status.Bad, ControlRed}
    };

    public View(Controller controller)
    {
        InitializeComponent();
        controller_ = controller;

        contoller_.FirstNameStatusChangedEvent += OnFirstNameStatusChanged;
    }

    private void txtFirstname_TextChanged(object sender, EventArgs e)
    { controller_.FirstName = txtFirstName.Text; }

    private void OnFirstNameStatusChanged(Controller.Status newStatus)
    { txtFirstName.BackColor = statusColors_[newStatus]; }
}

答案 2 :(得分:0)

您在代码中执行的大多数操作属于 Controller 类,因为它描述了逻辑。您的视图应该只描述用户界面并轻松访问UI组件。 Model 类应描述您的数据模型。

这个想法很简单: Controller 可以完成所有工作,但必须了解 View Model 。例如,当 View 被初始化时, Controller 设置所有逻辑(有点你已经在做什么)。当 Model 被分配给 Controller 时,它会将值设置为适当的UI控件,并执行相同操作以检索数据,并返回 Model

基本上,您将数据模型类提供给控制器,它会进行编辑并再次将您的数据作为模型类返回。

答案 3 :(得分:0)

如果可能的话,在经典ASP.NET中跟踪MVC会非常困难,所以我会基于MVP回复。

在您的第一个示例中,您正在尝试进行验证。验证姓氏是Presenter的责任。显示红色字段是View的责任。所以,你的视图类是这样的:

private void Page_Load()
{
    this._presenter = new Presenter();
}

private void txtLastname_TextChanged(object sender, EventArgs e)
{
    txtLastName.BackColor = presenter.IsLastnameValid(txtLastName.Text) ?
        ControlGood : ControlBad;
}

您的演示者课程将是这样的:

public Presenter()
{
    public bool IsLastNameValid(string lastname)
    {
        return string.IsNullOrEmpty(lastname);
    }
}

姓氏是你的模特。

请注意,我准备这些课程只是为了展示你将如何形成MVP结构。在现实世界中,有许多更好的方法可以进行验证。通常,您会将此方法用于您的业务,而不是验证。

答案 4 :(得分:0)

伊恩,

如果您希望控件立即验证,则需要使用javascript或jQuery。对于经典ASP.NET也是如此。由于您使用的是Code Behind方法,我假设您的验证等待回发。

以下示例来自NerdDinner项目。 NerdDinner是一个开源项目,作为ASP.NET MVC架构的一个例子。作者慷慨地提供了一个教程,可在http://nerddinnerbook.s3.amazonaws.com/Intro.htm

获得

在ASP.NET MVC中提交表单时,它会以FormCollection对象的形式进入相应的控制器:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
    Dinner dinner = dinnerRepository.GetDinner(id);

    try
    {
        UpdateModel(dinner);
        dinnerRepository.Save();
    }
    catch
    {
        ModelState.AddModelErrors(dinner.GetRuleViolations())
    }
    return RedirectToAction("Details", new { id = dinner.DinnerID });
}

UpdateModel获取表单值并尝试将它们填充到晚餐对象中。晚餐对象看起来像这样:

public partial class Dinner {
    public bool IsValid {
        get { return (GetRuleViolations().Count() == 0); }
    }
        public IEnumerable<RuleViolation> GetRuleViolations() {
        yield break;
    }
     public IEnumerable<RuleViolation> GetRuleViolations() {

        if (String.IsNullOrEmpty(Title))
            yield return new RuleViolation("Title is required", "Title");

        if (String.IsNullOrEmpty(Description))
            yield return new RuleViolation("Description is required", "Description");

        if (String.IsNullOrEmpty(HostedBy))
            yield return new RuleViolation("HostedBy is required", "HostedBy");

        if (String.IsNullOrEmpty(Address))
            yield return new RuleViolation("Address is required", "Address");

        if (String.IsNullOrEmpty(Country))
            yield return new RuleViolation("Country is required", "Address");

        if (String.IsNullOrEmpty(ContactPhone))
            yield return new RuleViolation("Phone# is required", "ContactPhone");

        if (!PhoneValidator.IsValidNumber(ContactPhone, Country))
            yield return new RuleViolation("Phone# does not match country", "ContactPhone");

        yield break;
    }
   partial void OnValidate(ChangeAction action) {
        if (!IsValid)
            throw new ApplicationException("Rule violations prevent saving");
    }
}

注意IsValid方法和RuleViolations枚举器。如果一切设置正确,您只需在此处定义验证,ASP.NET MVC将为您处理剩下的部分。

最终验证结果如下:

alt text

我鼓励您在http://nerddinner.codeplex.com/

获取NerdDinner应用程序和教程