ООП против заявления случая в приложении форм Windows - PullRequest
3 голосов
/ 30 апреля 2009

У меня есть вопрос о разработке программного обеспечения. Скажем, у меня есть форма окна с некоторыми элементами, и у меня есть объект customer. Клиент может быть, например, деловым, частным или корпоративным.

Теперь все решения о том, что произойдет в форме, будут зависеть от типа клиента. Например, некоторые элементы будут скрыты, определенный текст метки будет другим и т. Д.… События будут реагировать по-разному

Очевидно, что одним из способов кодирования этого будет использование оператора CASE каждый раз, когда необходимо принять решение. Другим способом было бы иметь класс Customer и 3 других класса, таких как BusinessCustomer, PrivateCustomer и CorporateCustomer, наследуемые от базового класса. В последнем случае возникает вопрос: как вы собираетесь встроить в него окна ...

Пожалуйста, поделитесь своей элегантностью, большое спасибо заранее.

Редакция: У меня просто есть идея: могу ли я встраивать формы в формы? Мои требования не требуют одновременного показа двух окон, поэтому мне не нужно использовать MDI. Но чтобы упростить мой дизайн, основываясь на комментариях некоторых пользователей, я хотел бы сохранить 3 различные формы клиентов и встраивать их в основную форму на лету. Таким образом, три GUI разделены, и мне не придется иметь дело с видимостью каждого элемента управления.

Теперь, кто-нибудь здесь имел опыт с этим? Я предполагаю, что я могу просто добавить форму в другую форму, например:

Form child_form = new Form();
parent_form.Controls.Add(child_form);

Ответы [ 6 ]

2 голосов
/ 30 апреля 2009

Эти решения действительно не должны приниматься в графическом интерфейсе. Вы должны иметь ViewModel позади вашего GUI, который принимает эти решения, и для которого вы пишете модульные тесты. (Или Presenter, или Controller - разные имена, которые означают примерно одно и то же: вывести решения из класса GUI и сделать что-то, что вы можете тестировать модулем.)

Тогда ваша ViewModel будет иметь, например, логическое свойство для каждого элемента, который будет отключен GUI, и метод для каждого действия, которое вы можете предпринять (CloseCustomerAccount () или что-то еще).

Пока форма создается для определенного типа клиента, и клиент не будет переходить на другой тип клиента в течение срока действия формы, вы можете просто передать свой объект Customer (в котором хранятся все фактические данные о клиенте) в конструктор ViewModel, а затем передайте вашу ViewModel в конструктор вашей формы. Форма может установить все свои свойства Enabled сразу после вызова InitializeComponent (). С другой стороны, если тип клиента может измениться, то вашей ViewModel необходимо предоставить некоторые события для перехвата формы, чтобы форма знала, когда следует повторно запустить логику «Включение».

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

Я бы позволил, чтобы ваш код был там руководством. Начните с самого простого подхода, который, вероятно, является падежом. Напишите юнит-тест для каждого интересующего вас поведения. Если операторы case начинают становиться слишком неудобными, добавьте потомок ViewModel для каждого типа клиента и начните извлекать операторы case в виртуальные методы. Ваши тесты поймают вас, если вы сделаете ошибку во время рефакторинга.

1 голос
/ 30 апреля 2009

Я согласен с ответом Джошуа Белдена. Скорее всего, проще всего поддерживать три отдельные формы для разных типов клиентов.

Кроме того, если вы еще не знали, вы можете получить класс Form и настроить его в производном классе Form. Это даже поддерживается дизайнером.

Однако я хотел бы предложить альтернативу:

Шаблон моста : отделите абстракцию от ее реализации, чтобы они могли различаться независимо друг от друга.

Что вы могли бы сделать так:

Создайте три отдельных UIImplementation класса. Эти классы могут настраивать пользовательский интерфейс и события для формы Customer. Чтобы получить доступ к закрытым членам формы, вам необходимо объявить классы UIImplementation как вложенные в класс CustomerForm. (Используйте частичные классы, чтобы разделить их на разные файлы). Если сама форма значительна, а настройки незначительны, это может быть хорошим вариантом. Сложно сказать.

1 голос
/ 30 апреля 2009

Если у вас есть 3 разных окна, каждое из которых работает с определенным типом клиентов, не будет особого смысла в работе с базовым классом или контрактом. Вы могли бы быть умными, хотя с классом фабрики, который берет класс клиента и определяет правильный экран для использования.

Я столкнулся с этим совсем немного. В итоге я получаю базовое окно, которое обрабатывает общий материал, а затем расширяю его для каждого конкретного типа.

0 голосов
/ 30 апреля 2009

Решение должно основываться на данных, а не на вашем коде.

Таким образом, если вы помечаете различные элементы управления как видимые в состоянии «A», «B» или «C», то один метод может посмотреть на его состояние и узнать, какие элементы управления сделать видимыми или нет.

Вы знаете, что сделали все правильно, когда добавление новых элементов управления для состояния "D" не требует изменений кода, кроме тех, которые необходимы для добавления самих элементов управления.

Вы также можете посмотреть, как разбить форму на 4 подформы: общая, подформа a, sub-b, а затем отобразить «Shared» и «Sub-a» вместе в родительской форме ...

0 голосов
/ 30 апреля 2009

Я бы пошел с подходом типа MVP и определил класс CustomerPresenter, который предоставляет логическое свойство, которое будет выводить состояние включения / выключения элементов управления вашего пользовательского интерфейса через привязку.

public class CustomerPresenter
{
  private Customer _customer;

  public CustomerPresenter(Customer customer)
  {
    _customer = customer;        
  }

  public bool EnableUI
  {
     get
     {
       //TODO: put your customer type basic logic here (switch statement or if/else)
       return _customer.Type == CustomerType.Business;
     }
  } 
}

public CustomerForm: WinForm
{
   private CustomerPresenter _customerPresenter;

   public CustomerForm(){};

   public CustomerForm(Customer customer)
   {
      _customerPresenter = new CustomerPresenter(customer);
   }      

   private void CustomerForm_Load(object sender, EventArgs e)
   {
      _someButton.DataBindings.Add("Enabled",_customerPresenter,"EnableUI");
   }

} 
0 голосов
/ 30 апреля 2009

Просто перейдите к трем классам, реализующим некоторый абстрактный интерфейс Customer. В вашем приложении у вас будет переменная customer типа Customer, и там будет храниться объект определенного типа Customer. Ваш графический интерфейс мог бы тогда просто полагаться на интерфейс и вызывать методы для переменной customer независимо от того, какой клиент фактически взаимодействует с GUI.

Посмотрите на эту статью .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...