Философия Java

         

Проектировка с наследованием


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

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

//: c07:Transmogrify.java

// Динамическое изменение поведения

// при композиции объекта.

abstract class Actor { abstract void act(); }

class HappyActor extends Actor { public void act() { System.out.println("HappyActor"); } }

class SadActor extends Actor { public void act() { System.out.println("SadActor"); } }

class Stage { Actor a = new HappyActor(); void change() { a = new SadActor(); } void go() { a.act(); } }

public class Transmogrify { public static void main(String[] args) { Stage s = new Stage(); s.go(); // Выводит "HappyActor"

s.change(); s.go(); // Выводит "SadActor"

} } ///:~

Объект Stage содержит ссылку на Actor, которая проинициализирована на объект HappyActor. Это означает, что go( ) предоставляет специфическое поведение. Но поскольку ссылка может быть перенаправлена на другой объект во время выполнения, то ссылка на объект SadActor может быть подставлена в a а затем посредством go( ) может быть изменена линия поведения. Так Вы наживаетесь на динамическом изменении во время работы программы. (Это так же называется статический шаблон (State Pattern). Смотрите для подробностей " Thinking in Patterns with Java", доступный с www.BruceEckel.com.) В противоположность, Вы не можете решить использовать наследование с различными типами в режиме выполнения, типы должны быть полностью определены на стадии компиляции.

Основная линия поведения при этом может быть выражена фразой "Используй наследование для выражения различия в поведении и поля для выражения различий в значениях". В предыдущем примере использовались оба принципа из высказывания: два различных класса были наследованы для получения различий в методе act( ), а Stage использует композицию для изменения своего значения. В этом случае, такое изменение означает и изменение в поведении метода.



Содержание раздела