2015-01-04 2 views
-1

Я пытаюсь создать всеобъемлющий abstractBaseClass, который определяет способ создания всех производных классов, но позволяет производным классам специализировать/агрегировать поля и методы, используемые в процессе создания. Вот упрощенный пример:Определить методы конструктора базового класса в производных классах

public abstract class BaseClass 
{ 
    public List<String> list; 

    public BaseClass() 
    { 
     defineList(); 
     optionalDoSomething(); 
     doSomething(); 
    } 

    protected void defineList() 
    { 
     list = new List<String>(); 
    } 

    protected void doSomething() 
    { 
     // do something w/ list here 
    } 

    protected void optionalDoSomething() {} 
} 

public class DerivedClass : BaseClass 
{ 
    protected void defineList() 
    { 
     base.defineList(); 
     list.Add("something"); 
    } 

    public DerivedClass() : base() { } 
} 

public class SecondDerivedClass : DerivedClass 
{ 
    protected void defineList() 
    { 
     base.defineList(); 
     list.Add("somethingElse"); 
    } 

    protected void optionalDoSomething() 
    { 
     // do something special 
    } 

    public SecondDerivedClass() : base() { } 
} 

Это освободит все производные классы от того, чтобы воссоздать ту же логику инициализации, и каждый производный класс должен только «переписать» необходимые поля и методы, используемые в процессе создания (и, возможно, в другом месте класса).

Проблема:

  1. Я не могу отметить BaseClass 'методы, как virtual, так как вы не можете вызвать virtual методы базового конструктора (в любом случае, я не хотел бы использовать virtual методы, поскольку, например, Я бы не хотел, чтобы DerivedClass использовал метод SecondDerivedClass 'defineList).

  2. Я могу отметить их abstract, но тогда я не смог бы поставить «реализации по умолчанию» в BaseClass, и каждый производный класс должен был бы реплицировать/реализовать эти значения по умолчанию. Кроме того, класс SecondDerived все равно должен был бы «переопределить» реализации DerivedClass.

  3. Не работает простое использование ключевого слова new «hide» менее производного класса.

Каков правильный способ получить этот шаблон?

TLDR: согласно мой комментарий ниже: Если BaseClass является abstract класс с методом A и DerivedClass является класс, производный от BaseClass (не обязательно прямым потомком BaseClass), то вызов A в BaseClass 'конструктор должен вызвать A() в каждом классе иерархии наследования до DerivedClass (но не более). Мы можем предположить, что A (вынужденный быть) определен на каждом промежуточном классе.

+0

Я не очень понимаю ваш вопрос. Прежде всего, хотя, конечно же, не рекомендуется, законно вызывать виртуальных членов из конструктора. Во-вторых, в вашем примере единственное, что делают методы 'defineList()', это добавить элементы в поле 'list' (которое не должно быть' public', и, откровенно говоря, в большинстве сценариев будет ''private'_, а не даже 'protected'), что вы могли бы так же легко сделать в каждом конструкторе каждого класса. В других сценариях вы просто передадите инициализированные данные из более производных конструкторов вплоть до конструкторов базового класса. –

+0

Я не буду называть 'virtual' методы в конструкторе. Кроме того, это упрощенный пример, но в целом методы, вызываемые в конструкторе 'BaseClass', могут делать другие вещи. В конечном счете, конструктор «BaseClass» должен «накапливать» некоторые данные, а затем вызывать методы, обрабатывающие эти данные. Поскольку обработка этих данных будет одинаковой для * большинства * производных классов, эти классы должны будут предоставить больше данных (например, 'defineList') до того, как будет вызываться метод обработки (например,' doSomething'). Разрешить производным классам «перезаписывать» другие методы не часто случаются. – jayflo

+0

«методы, называемые конструктором BaseClass, могли бы делать другие вещи», - пожалуйста, укажите пример кода, который иллюстрирует эти «другие вещи». Поскольку вопрос задан до сих пор, все, что у вас есть, не проблема. Это, безусловно, приведет (и привело) к целому ряду попыток ответить, но, как вы можете видеть, предложения находятся вне пределов доски, и без явного заявления о проблемах трудно понять, как вопрос и ответы могут оказаться полезными в целом другим. –

ответ

1

Я думаю, что вам следует обратиться к template-method-design-pattern

Определите скелет алгоритма в операции, отложив некоторые шаги к подклассам. Template Method позволяет подклассам переопределять определенные этапы алгоритма без изменений структуры алгоритма.

вы можете попробовать что-то подобное этому

abstract class AbstractClass 
    { 
    public List<String> list; 
    public abstract void PrimitiveOperation1(); 

    public void TemplateMethod() 
    { 
     //initialize code that each class should perform 
     PrimitiveOperation1(); 
    } 
    } 

class DerivedClass: AbstractClass 
    { 
    public override void PrimitiveOperation1() 
    { 
     list.Add("something"); 
    } 
    } 

использования

AbstractClass abstractClass1 = new DerivedClass(); 
abstractClass1.TemplateMethod(); 
0

Один из способов добиться того, что вы хотите, чтобы добавить явный Initialize метод базового класса и сделать логику initializaiton там, например:

public abstract class BaseClass 
{ 
    public List<String> list; 

    public BaseClass() 
    { 

    } 

    public void Initialize() 
    { 
     defineList(); 
     optionalDoSomething(); 
     doSomething(); 
    } 
} 
1

Попробуйте это решение, реализация осуществляется с защищенными виртуальными методами , так что его не видно снаружи и не требуется в производных классах:

public abstract class BaseClass 
    { 
     public List<String> List { get; protected set; } 

     protected BaseClass() 
     { 
      defineList(); 
      optionalDoSomething(); 
      doSomething(); 
     } 

     protected void defineList() 
     { 
      // default implementation here 
      List = new List<String>(); 

      internalDefineList(); 
     } 

     protected void doSomething() 
     { 
      // default implementation here 
      internalDoSomething(); 
     } 

     protected void optionalDoSomething() 
     { 
      // default implementation here 
      internalOptionalSomething(); 
     } 

     protected virtual void internalDefineList() 
     { 
     } 

     protected virtual void internalDoSomething() 
     { 
     } 

     protected virtual void internalOptionalSomething() 
     { 
     } 
    } 

    public class DerivedClass : BaseClass 
    { 
     protected override void internalDefineList() 
     { 
      var list = List; 
     } 

     protected override void internalDoSomething() 
     { 
     } 

     // this method is not required 
     /*   
     protected override void internalOptionalSomething() 
     { 
     } 
     */ 
    } 
+0

Это близко и хорошо (!), Но если я подкласс 'DerivedClass', скажем' SecondDerivedClass: DerivedClass' и 'override' 'внутренний метод там, то любой экземпляр' DerivedClass' будет вызывать 'SecondDeriveClass'' внутренний». В принципе, если класс происходит из 'BaseClass' и имеет метод' A', то вызов 'A' из этого производного класса должен вызывать' A' на всех менее производных классах до и включая 'BaseClass' ... и он не должен вызовите 'A' на любые« более производные »классы. – jayflo

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