2012-01-20 2 views
1

У меня есть абстрактный базовый класс и два производных класса. Базовый класс содержит 6 свойств, которые все могут поддерживаться на форме.Что такое хороший способ обработки нескольких типов объектов в одной и той же форме?

В двух производных классах есть 1 дополнительное свойство. Эти два свойства также могут поддерживаться в одной и той же форме.

В моей форме у меня сейчас такой код:

btnSomething.visible = (myObject is DerivedA); 
    pnlPanel.visible = !(myObject is DerivedA); 

    if(myObject is DerivedA) 
    myBindingSource.DataSource = myObject as DerivedA 

    mySecondBindingSource = myObject; 

Я не очень доволен этим подходом, он пахнет. Итак, мой вопрос: что является опрятным/хорошим способом сделать это более OO? Потому что это, возможно, что в будущем DerivedC приходит ...

Я думаю, что такой подход нарушает принцип OCP (и, возможно, другие принципы)

ответ

2

Вы можете использовать полиморфизм и наследование здесь:

Определить интерфейс

interface ICommonFeatures 
{ 
    bool ContainsFoo {get;} 
    //yak-yak 
} 

Тогда ваши производные классы реализуют его

class DerivedA: ICommonFeatures 
{ 
    bool ContainsFoo {get {return true;}} 
    //so-and-so 
} 
class DerivedB: ICommonFeatures 
{ 
    bool ContainsFoo {get {return false;}} 
    //this-and-that 
} 

И когда вы используете его, вы имеете дело только с интерфейс

ICommonFeatures foo = new DerivedB(); 

btnSomething.visible = foo.ContainsFoo; 
pnlPanel.visible = foo.Prop2; 
myBindingSource.DataSource = foo.CurrentDataSource 
+0

Я думал в этом направлении, но в вашем случае я могу прочитать 'foo.Prop1' как' foo.ShowButtonSomething'? Итак, в основном, каждый элемент управления графическим интерфейсом, который зависит от класса Derived, вы создаете логическое свойство? – Martijn

+0

Да, но в интерфейсе вы должны скорее поставить логическую нагрузку, а не пользовательский интерфейс. Итак 'ShowButtonSomething' =>' ContainsFoo'. Затем глубже в вашей логике вы убедитесь, что если класс содержит foo, вы хотели бы отобразить кнопку. Такой подход сохранит логику, инкапсулированную в классе, и презентация будет отделена от модели (что всегда является хорошей идеей). Другое дело, что ваши GUI-элементы управления будут зависеть от абстракции - интерфейса или абстрактного класса, если вы предпочитаете. – oleksii

+0

Я думаю, что получаю его, поэтому в «ICommonFeatures» у меня может быть свойство «bool ContainsCompanyAddress», и в моей форме я устанавливаю 'txtCompanyAddress.visible = foo.ContainsCompanyAddress'? – Martijn

0

Сумасшедшая идея была бы сделать расширяемый пользовательский интерфейс. Вы можете сделать форму, реализующую базовую форму.

Затем в классе производной формы вы должны вставлять отсутствующие элементы управления и поведение для своего класса модели. В производном классе или библиотеке вы можете привязать некоторую привязку к правильной форме.

Хороший подход для этого будет следовать некоторым принципам MVP.

Надеется, что это поможет вам как-то ..

+0

Я действительно выполнял такую ​​реализацию, но в своем решении у меня были разные библиотеки, реализующие набор интерфейсов и базовых классов, и каждая из библиотек могла бы быть получена из основной формы конфигурации. Затем в основном приложении я бы указал либо форму по умолчанию, либо пользовательскую, реализованную библиотекой. –

0

Я хотел бы объявить абстрактный метод булева/свойство для каждого элемента управления, которые должны вести себя в соответствии с основным типом.

Например

// to handle pnlPanel.visible = !(myObject is DerivedA);  
abstract bool SupportsPanel{get;} 

Как для связывания источников, я хотел бы также предоставить некоторые виртуальные BindingSource и SecondBindingSource свойства.

Может быть что-то вроде (чисто пример)

public abstract class BaseClass 
{ 
    // All your exising class declaration here 

    public virtual object BindingSource 
    { 
     get 
     { 
      // By default, a BaseClass is not valid as a binding source 
      return null; 
     } 
    } 

    public virtual object SecondBindingSource 
    { 
     get 
     { 
      // By default, a BaseClass is a valid Second Binding source 
      return this; 
     } 
    } 
} 

public class DerivedA : BaseClass 
{ 
    // All your exising class implementation here 

    public override object BindingSource 
    { 
     get 
     { 
      // For DerivedA, the data sourse is itself. 
      // other classes might have their own implementations. 
      return this; 
     } 
    } 

    // No need to override SecondBindingSource as the BaseClass one works as expected. 

} 

Таким образом, ваш код может перестать беспокоиться о типе объекта и выглядеть следующим образом:

myBindingSource.DataSource = myObject.BindingSource; 
mySecondBindingSource = myObject.SecondBindingSource; 

Надеется, что это помогает.

+0

Не могли бы вы предоставить (фиктивный) пример того, как обращаться с связующими ресурсами? – Martijn

+0

@Martijn Я обновил свое сообщение для вас. Это немного отличается от того, о чем я думал в начале, но идея одна и та же: используйте свой объект как «BaseClass» и инкапсулируйте то, что специфично только внутри производных классов. – remio

Смежные вопросы