Когда вызывать base.method () и какой код должен идти в base.method ()? - PullRequest
3 голосов
/ 26 июня 2009

В следующем примере автор производного класса должен вызвать base.Add (). Если это произойдет 1-го, база может сделать один вид кода. Если это произойдет в последний раз, база может сделать другую логику (см. Пример). Я не вижу возможности иметь оба пути. И простым решением было бы вообще перестать вызывать базовый метод, потому что база никогда не узнает, вызывается ли он первым, последним или посередине или дважды!

Что такое объектно-ориентированный способ борьбы с этим? Должен ли я просто прекратить помещать код в базовые методы, потому что я никогда не узнаю предварительные и постусловия?

РЕДАКТИРОВАТЬ: цель состоит в том, чтобы иметь класс бизнес-объектов, который выполняет операции CRUD. Повторяющийся код будет перемещен в базовый класс. Например, проверяя, видит ли перед добавлением записи идентификатор бизнес-объекта 0, и проверяя, что после сохранения идентификатор бизнес-объекта> 0.

namespace StackOverFlowSample
{
    class BusinessObjectBase
    {
        private bool _isNew;
        private int _id;
        public virtual void Add(string newAccount)
        {
            //Code that happens when subclasses run this method with the 
            //same signature

            //makes sense if base is called 1st
            if(_isNew && _id>0) throw new InvalidOperationException("Invalid precondition state");

            //makes sense if bae is called 2nd
            if (!_isNew && _id == 0) throw new InvalidOperationException("Invalid post condition state");
        }
    }
    class BusinessObject : BusinessObjectBase {
        public override void Add(string newAccount)
        {
            //doesn't make sense, because base will need to be called again.
            base.Add(newAccount);//pre validation, logging

            //Save newAccount to database

            //doesn't make sense, because base has already been called
            base.Add(newAccount);  //post validation, logging
        }
    }
}

Ответы [ 3 ]

3 голосов
/ 26 июня 2009

Если вам нужен безопасный способ введения проверок условий до и после, вы можете сделать Add не виртуальным и вместо этого иметь другой метод (AddInternal или что-то в этом роде), который производные классы могут (или должны?) Переопределять:

namespace StackOverFlowSample
{
    abstract class BusinessObjectBase
    {
        private bool _isNew;
        private int _id;

        protected abstract void AddInternal(string newAccount);
        public void Add(string newAccount)
        {
            if(_isNew && _id>0) throw new InvalidOperationException("Invalid precondition state");
            AddInternal(newAccount);    
            if (!_isNew && _id == 0) throw new InvalidOperationException("Invalid post condition state");
        }
    }
    class BusinessObject : BusinessObjectBase {
        protected override void AddInternal(string newAccount)
        {
            //Save newAccount to database
        }
    }
}
2 голосов
/ 26 июня 2009

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

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

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

Имеет ли смысл что-то вроде:

class BusinessObjectBase
{
    public void Add(string newAccount)
    {
        if(_isNew && _id>0) throw new InvalidOperationException("Invalid precondition state");

        AddOperation(newAccount);

        if (!_isNew && _id == 0) throw new InvalidOperationException("Invalid post condition state");
    }

    protected void virtual AddOperation(string newAccount)
    {
        // Code from base AddOperation
    }

}
class BusinessObject : BusinessObjectBase {
    protected override void AddOperation(string newAccount)
    {
        //custom AddOperation
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...