Наследование в сравнении с композицией ActionScript 

 

 

Композиция, представляющая альтернативный вид отношений между объектами, 

зачастую соперничает с наследованием в качестве методики объектно-ориентиро- 

ванного дизайна. В композиции один класс (внешний) хранит экземпляр другого 

класса (внутреннего) в переменной экземпляра. Внешний класс поручает работу 

внутреннему классу, вызывая методы над этим экземпляром. Вот базовый подход, 

представленный обобщенным кодом: 

// Внутренний класс является аналогом суперкласса в наследовании 

public class BackEnd { 

public function doSomething ( ) { 

// Внешний класс является аналогом подкласса в наследовании 

public class FrontEnd { 

// Экземпляр внутреннего класса сохраняется в закрытой переменной 

// экземпляра, в данном случае в закрытой пременной be 

private var be; 

// Конструктор создает экземпляр внутреннего класса 

public function FrontEnd ( ) { 

be = new BackEnd( ); 

// Этот метод поручает работу методу doSomething( ) класса BackEnd 

public function doSomething ( ) { 

be.doSomething( ); 

Обратите внимание, что класс FrontEnd не расширяет класс BackEnd. Композиция 

не требует использования собственного особого синтаксиса, как это происходит 

с наследованием. Более того, внешний класс может использовать подмножество 

методов внутреннего класса, все методы или добавлять собственные несвязанные 

методы. Имена методов во внешнем классе могут полностью совпадать с именами 

методов во внутреннем классе или совершенно отличаться. Внешний класс может 

ограничивать, расширять или переопределять возможности внутреннего класса, 

играя такую же роль, как подкласс в наследовании. 

Ранее в этой главе было описано, как с помощью наследования класс Square может 

ограничивать поведение класса Rectangle. В листинге 6.2 показано, как одно и то 

же отношение между классами может быть реализовано с использованием  

композиции вместо наследования. В предлагаемом коде класс Rectangle остался  

неизмененным. Однако на этот раз класс Square не расширяет Rectangle. Вместо этого 

в классе Square описана переменная г, содержащая экземпляр класса Rectangle. 

Фильтрация всех операций над экземпляром, хранящимся в переменной г,  

происходит через public-методы класса Square. Класс Square переадресует, или делегирует, 

вызовы методов экземпляру, хранящемуся в переменной г. Обратите внимание, что, 

поскольку метод set Size ( ) класса Square не перекрывает метод setSize ( ) 

класса Rectangle, сигнатура метода setSize ( ) класса Square не обязана  

совпадать с сигнатурой метода set Size ( ) класса Rectangle. В методе setSize ( ) 

класса Square можно определить один-единственный параметр, в отличие от метода 

setSize ( ) класса Rectangle, в котором определено два параметра. 

 

Листинг 6.2. Пример отношения композиции 

// Класс Rectangle 

public class Rectangle { 

protected var w = 0; 

protected var h = 0; 

public function Rectangle (width, height) { 

setSize(width, height); 

public function setSize (newW, newH) { 

w = newW; 

h = newH; 

public function getArea ( ) { 

return w * h; 

// Это новый класс Square 

public-class Square { 

private var r; 

public function Square (side) { 

г = new Rectangle(side, side); 

public function setSize (side) { 

r.setSize(side, side); 

public function getArea ( ) { 

return r.getArea( ); 

Отношения «является», «имеет» и «использует». В разговорной речи отношение 

наследования, присущее объектно-ориентированным языкам программирования,  

называется отношением «является» (Is-А), поскольку экземпляр подкласса в  

буквальном смысле можно рассматривать как экземпляр его суперкласса (то есть экземпляр 

подкласса может быть использован везде, где это допустимо применением экземпляра 

его суперкласса). В предыдущем примере полиморфизма экземпляр класса Circle 

«является» экземпляром класса Shape, поскольку класс Circle унаследован от 

Shape и, следовательно, может использоваться везде, где используется Shape. 

Отношение композиции называется отношением «имеет», поскольку внешний класс 

содержит экземпляр внутреннего класса. Не следует путать отношение «имеет» с  

отношением «использует», когда некоторый класс создает объект другого класса, но не 

присваивает созданный объект переменной экземпляра. В отношении «использует» 

класс использует объект, а затем выбрасывает его. Например, класс Circle мо- 

 

жет хранить числовое значение цвета в переменной color («имеет» объект класса 

uint), но впоследствии может временно воспользоваться объектом класса Color, 

чтобы отобразить этот цвет на экране («использует» объект класса Color). 

В листинге 6.2 класс Square «имеет» экземпляр класса Rectangle и налагает на 

него ограничения, которые фактически превращают класс Rectangle в Square. 

В случае с классами Square и Rectangle отношение «является» выглядит более 

естественным, однако можно использовать и отношение «имеет». В этой связи 

возникает вопрос: какое отношение лучше? 

Когда использовать композицию вместо наследования. Листинг 6.2 поднимает 

серьезный вопрос проектирования. Как сделать выбор между композицией и  

наследованием? Вообще, достаточно легко определить ситуацию, в которой  

наследование неприменимо. Экземпляр класса AlertDialogB приложении «имеет» кнопку 

ОК, но сам экземпляр класса Alert Dialog кнопкой OK не «является». Сложнее 

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

наследование, используемое для создания отношения между двумя классами,  

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

подхода, какой из них окажется лучшим выбором? 

Для новичков в объектно-ориентированном программировании будет  

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

предпочтение отдают композиции, а не наследованию. На самом деле некоторые 

известные теоретики в области объектно-ориентированного проектирования  

недвусмысленно советуют использовать композицию вместо наследования  

(книга «Design Patterns: Elements of Reusable Object-Oriented Software» издательства 

Addison-Wesley, авторы Эрих Гамма (Erich Gamma) и др.). Таким образом, здравый 

смысл подсказывает нам хотя бы рассмотреть возможность применения  

композиции даже в том случае, когда выбор наследования кажется очевидным. И все-таки, 

вот несколько общих рекомендаций, которые помогут сделать выбор между  

наследованием и композицией: 

□ если вы желаете воспользоваться преимуществом полиморфизма, рассмотрите 

возможность применения наследования; 

□ когда классу необходимы сервисы другого класса, рассмотрите возможность 

использования отношения композиции; 

□ если поведение разрабатываемого вами класса очень похоже на поведение  

существующего класса, рассмотрите возможность применения отношения  

наследования. 

Дополнительные советы по выбору подхода проектирования между  

композицией и наследованием можно найти в прекрасной статье Java World Билла Веннера 

(Bill Venner), которая хранится в архиве на сайте автора: http://www.artima.com/ 

designtechniques/compoinh.php. Мистер Веннер приводит неоспоримые  

доказательства, что: 

□ изменение кода, использующего композицию, влечет за собой меньше  

последствий, чем изменение кода, использующего наследование; 

□ код, основанный на наследовании, зачастую выполняется быстрее, чем код, 

в основе которого лежит композиция. 




BACK NEXT

Сайт является частным собранием материалов и представляет собой любительский информационно-образовательный ресурс. Вся информация получена из открытых источников. Администрация не претендует на авторство использованных материалов. Все права принадлежат их правообладателям