简体   繁体   中英

Define base class constructor methods in derived classes

I am trying to create a comprehensive abstract BaseClass that defines the way in which all derived classes are created, but allows derived classes to specialize/aggregate the fields and methods used in the creation process. Here is a simplified example:

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() { }
}

This would free all derived classes from having to recreate the same initialization logic, and each derived class would only need to "overwrite" the necessary fields and methods used in the create process (and possibly elsewhere in the class).

The problem:

  1. I cannot mark BaseClass ' methods as virtual since you cannot call virtual methods in a base constructor (in any case, I would not want to use virtual methods since, for example, I would not want DerivedClass to use SecondDerivedClass ' defineList method).

  2. I can mark them abstract , but then I would not be able to put "default implementations" in BaseClass and each derived class would have to replicate/implement those defaults. Also, SecondDerived class would still need a way to "override" the implementations of DerivedClass .

  3. It does not work to simply use the new key word "hide" less derived class' methods.

What is the correct way to obtain this pattern?

TLDR: as per my comment below: If BaseClass is an abstract class with method A , and DerivedClass is a class derived from BaseClass (not necessarily a direct child of BaseClass ), then calling A in BaseClass ' constructor should call A() in every class in the inheritance hierarchy up to and including DerivedClass (but no further). We can assume that A (forced to be) defined on every intermediate class.

Try this solution, the implementation is implemented with protected virtual methods, so its not visible from the outside and not required in derived classes:

    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()
        {
        }
        */
    }

I think that you should refer to template-method-design-pattern

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

you can try something similar to this

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");
    }
  }

usage

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

One way to achieve what you want is to add an explicit Initialize method to the base class and do the initializaiton logic there, eg:

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

    public BaseClass()
    {

    }

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM