Что такое MVC-версия этого кода? - PullRequest
1 голос
/ 07 июня 2009

Я пытаюсь обдумать, как усовершенствовать свой код: взять простую процедуру и разделить ее на 5 или 6 методов в 3 или 4 классах.

я быстро нашел три простых примера кода как я сейчас его пишу . Может кто-нибудь преобразовать их в запутанную версию 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 age совершенно необязательно. Если введен возраст , то он будет действительным:

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 ]

2 голосов
/ 07 июня 2009

Целью паттернов MVC / MVP является не запутывание, а разделение интересов . Запутывание до (conceal the) intended meaning in communication, making communication confusing, intentionally ambiguous, and more difficult to interpret: ref . Использование шаблонов - сделать код чище и более понятным. Я предлагаю вам начать с чтения статей в Википедии на MVC и MVP .

Оба шаблона - это способы структурирования вашего кода таким образом, чтобы ваше приложение было разбито на элементы, которые выполняют конкретные цели, имеющие четко определенные границы взаимодействия. Вместо того, чтобы иметь код, специально предназначенный для решения бизнес-задач, обработки ввода-вывода и представления в различных классах приложения, эти проблемы разделены и изолированы в различных архитектурных компонентах. Эти архитектурные элементы изолированы друг от друга границами взаимодействия (интерфейсами), что делает их более независимыми друг от друга и их легче модифицировать, не затрагивая приложение в целом.

1 голос
/ 07 июня 2009

Основная идея, которую я имею при реализации MVC для Windows Forms, заключается в том, что я хочу провести модульные тесты для моей модели и моего контроллера. Чтобы добиться этого, мой контроллер не должен ничего знать о представлениях, использующих его, и поэтому любые уведомления, которые должны обрабатываться на уровне пользовательского интерфейса, реализуются как события. В вашем примере мой контроллер будет выглядеть примерно так:

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]; }
}
0 голосов
/ 07 июня 2009

Ian

Если вы хотите, чтобы элементы управления проверялись немедленно, вам нужно использовать 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

Я рекомендую вам получить приложение и учебное пособие по NerdDinner на http://nerddinner.codeplex.com/

0 голосов
/ 07 июня 2009

Было бы очень трудно следовать MVC в классическом ASP.NET, если это возможно, поэтому я отвечу на основе MVP.

В первом примере вы пытаетесь выполнить проверку. Проверка фамилии является обязанностью докладчика. Отображение красного поля является обязанностью 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. В реальном мире есть много лучших способов сделать проверку. Обычно вы используете этот подход для своего бизнеса вместо проверки.

0 голосов
/ 07 июня 2009

Большая часть того, что вы делаете в своем коде, принадлежит классу Controller , поскольку он описывает логику. Ваш View должен просто описывать пользовательский интерфейс и обеспечивать легкий доступ к компонентам пользовательского интерфейса. Модель класс должен описывать вашу модель данных.

Идея проста: Контроллер делает все, но он должен знать о Вид и Модель . Например, когда View инициализирован, Controller устанавливает всю логику (вроде того, что вы уже делаете). Поскольку Модель назначена на Контроллер - он устанавливает значения в соответствующие элементы управления пользовательского интерфейса и делает то же самое для извлечения данных и возврата, как Модель .

Таким образом, вы в основном предоставляете свой класс модели данных контроллеру, он выполняет редактирование и возвращает ваши данные как класс модели снова.

...