Наследование или состояние? - PullRequest
3 голосов
/ 21 мая 2009

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

Ответы [ 8 ]

5 голосов
/ 21 мая 2009

Один такой рефакторинг называется Заменить условный на полиморфизм .

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

2 голосов
/ 21 мая 2009

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

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

Если операторы следует использовать для сравнения типов естественного упорядочения (<,>, == и т. Д.) Или для проверки, является ли что-либо нулевым.

2 голосов
/ 21 мая 2009

Как правило, это не очень хорошая практика объектно-ориентированного программирования, чтобы иметь такой код:

var chioce = PAINT_SCREEN_BLUE

if (choice == PAINT_SCREEN_BLUE):
    paintScreen(blue)
else if (choice == PAINT_SCREEN_RED):
    paintScreen(red)
else if (choice == PAINT_SCREEN_GREEN):
    paintScreen(green)

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

interface ScreenPainter:
    function perform()

class BlueScreenPainter implements ScreenPainter:
    function perform():
        paintScreen(blue)

...

// The conditional block can be replaced with the following call:
var choice = PAINT_SCREEN_BLUE

ScreenPainter p = Painters.getPainter(choice)
p.perform()

Однако эта практика определенно не должна применяться для всех условий, однако, когда речь идет о длинных switch блоках или if-elseif-else блоках, во многих случаях использование наследования сделает ваш код более расширяемый и надежный.

1 голос
/ 21 мая 2009

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

Лучший способ развить способность отвечать на нее в любой конкретной ситуации - это набраться опыта: эксперимент. Попробуйте оба способа, где вы можете сделать это разумно. (Очевидно, что вы не хотите переворачиваться назад и вперед в ситуациях, когда для этого нужно изменить тысячу строк кода.) Что сработало лучше? Что тебе было лучше? Почему?

Сделайте это достаточно, и вы скоро достигнете уровня знаний, когда вам больше не нужен общий совет, и люди начнут спрашивать вас, как вы знаете, что делать в той или иной конкретной ситуации. (Вы не сможете объяснить это; это часть специализации. См. Модель приобретения навыков Дрейфусом для более подробной информации.

0 голосов
/ 21 мая 2009

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

Использование наследования означает, что тип (упрощенный до одинарного или двоичного) учитывается в наследовании:

class Operator
{
    abstract string ToString();
}
class UnaryOperator : Operator
{
    Expression Expression { get; }
    override string ToString() {...}
}
class BinaryOperator : Operator
{
    Expression LeftExpression { get; }
    Expression RightExpression { get; }
}
class AdditionOperator : BinaryOperator
{
    override string ToString()
    {
        return this.LeftExpression.ToString() + "+" + this.RightExpression.ToString();
    }
}

В отличие от:

class Operator
{
    Expression LeftExpression { get; }
    Expression RightExpression { get; }

    OperatorType Type { get; }

    string ToString()
    {
        switch(this.Type)
        {
            case OperatorType.Addition:
                return this.LeftExpression.ToString() + "+" + this.RightExpression.ToString();
            case OperatorType.Negation:
                return "-" + this.LeftExpression.ToString();
            case ...:
        }
    }
}
enum OperatorType
{
    // Unary operators
    Negation,

    // Binary operators
    Addition,
    Subtraction,
    Multiplication
}

Здесь унарный оператор не имеет выражения Left и Right, а просто выражение. Это означает, что вы должны ввести соглашение, что левый используется, а правый равен нулю. ToString должен будет проверить OperatorType; как и любой другой метод, который должен действовать в зависимости от оператора.

Последний подход чаще всего встречается в реализациях XML DOM, где XmlNode - это практически все, что может содержать любой узел XML ... когда-либо. Это делает для некоторых очень запутанных ситуаций:

  • Как атрибут или текстовый узел могут иметь дочерние узлы?
  • Как документ может иметь дочерние узлы, если он может иметь только один? (Это не обязательно должна быть коллекция)
  • Как у документа может быть ParentNode?
  • Каким образом документ может иметь значение?
  • 1024 * И т.д. *
0 голосов
/ 21 мая 2009

По моему мнению, эти два не являются взаимоисключающими. Обычно я использую наследование, когда у меня есть 2 или более классов, которые имеют общую функциональность.

0 голосов
/ 21 мая 2009

Вот то, с чем я столкнулся на днях

PHP мой язык выбора

class Cache {

    public function __construct($resource) {

     // if statement to determine from type if it is a file, url or string. instead, change it to accept a string

    }

}

или ... это могло быть продлено

class cacheURL extends Cache {

    public function __construct($url) {

        $string = file_get_contents($url);

        parent::__construct($string);
    }

}

Грубый пример, но я надеюсь, что вы поймете мой дрейф ....

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