2010-10-20 2 views
10

Большинство дизайнерских книг patten говорят, что мы должны «Использовать композицию объекта над наследованием класса».Недостаток композиции объекта над наследованием класса

Но может ли кто-нибудь дать мне пример, что наследование лучше, чем состав объекта.

ответ

4

В Java, когда вы наследуете класс, ваш новый класс также автоматически становится подтипом исходного типа класса. Поскольку это подтип, он должен придерживаться Liskov substitution principle.
Этот принцип в основном говорит о том, что вы должны иметь возможность использовать подтип везде, где ожидается супертип. Это серьезно ограничивает, как поведение вашего нового унаследованного класса может отличаться от исходного класса.
Никакой компилятор не сможет заставить вас придерживаться этого принципа, но вы можете столкнуться с проблемами, если этого не произойдет, особенно когда другие программисты используют ваши классы.

В языках, разрешающих подклассирование без подтипов (например, CZ language), правило «Использовать композицию объекта над наследованием» не так важно, как в таких языках, как Java или C#.

+0

>> Если вы программировали на языке, который позволяет подклассифицировать без подтипирования, вы имеете в виду большинство языков сценариев? – Howard

+2

Мне нравится, что автор вопроса показывает, что он хотел получить ответ, противоположный тому, что было задано. Нам было предложено предоставить встречный пример, где наследование было бы более уместным. Тем не менее, он должен отказаться и принять еще один пример, когда наследство снова отсасывает. Это тайна. ООП доминирует над миром, но его главная особенность, наследование, никогда не должна использоваться в пользу старой хорошей структурной композиции! Может быть, мы должны предпочесть условные обозначения над полиморфизмом также потому, что полиморфизм достигается через (всегда) плохое наследование в java? – Val

+1

Может быть, Java - это мусор, потому что на основе таких вещей, как Integer, расширяет Number и ByteInputStream расширяет InputStream, и каждый объект получает из объекта блокировку, хеш и методы равенства. Очевидно, что если наследование ничего плохого, то java ошибочно с самого начала. – Val

11

Наследование подходит для is-a отношений. Это плохо подходит для отношений has-a.

Поскольку большинство отношений между классами/компонентами попадают в has-a ведра (например, Car класса, скорее всего, не HashMap, но он может иметь HashMap), тогда следует композиция часто является лучшей идеей для моделирования отношений между классами, а не наследованием.

Это не означает, однако, что наследование не является полезным или не является правильным решением для некоторых сценариев.

7

Мой простой ответ заключается в том, что вы должны использовать наследование для поведенческих целей. Подклассы должны переопределять методы для изменения поведения метода и самого объекта.

Эта статья (интервью с Эрихом Гамма, одним из членов GoF) четко объясняет, почему Favor object composition over class inheritance.

0

Просто думать о нем, как имеющий «это-а» или «имеет-A» отношения

В этом примере человеческого «является разновидностью» животных, и он может наследует различные данные класс животных. Поэтому используется Наследование:

abstract class Animal { 
    private String name; 
    public String getName(){ 
     return name; 
    } 
    abstract int getLegCount(); 
} 

class Dog extends Animal{ 
    public int getLegCount(){ 
     return 4; 
    } 
} 

class Human extends Animal{ 
    public int getLegCount(){ 
     return 2; 
    } 
} 

Состав имеет смысл, если один объект является владельцем другого объекта. Как объект Human, владеющий объектом Dog. Таким образом, в приведенном ниже примере человеческого объекта «имеет-а» Dog объект

class Dog{ 
    private String name; 
} 
class Human{ 
    private Dog pet; 
} 

надежда, что помогло ...

0

Это фундаментальный принцип построения хорошей ООД. Вы можете назначить поведение классу динамически «во время выполнения», если вы используете композицию в своем дизайне, а не наследование, как в Strategy Pattern. Скажем,

interface Xable { 
doSomething(); 
} 

class Aable implements Xable { doSomething() { /* behave like A */ } } 
class Bable implements Xable { doSomething() { /* behave like B */ } } 

class Bar { 
Xable ability; 

public void setAbility(XAble a) { ability = a; } 

public void behave() { 
ability.doSomething(); 
} 

} 
/*now we can set our ability in runtime dynamicly */ 

/*somewhere in your code */ 

Bar bar = new Bar(); 
bar.setAbility(new Aable()); 
bar.behave(); /* behaves like A*/ 
bar.setAbility(new Bable()); 
bar.behave(); /* behaves like B*/ 

если вы использовали наследование, то «Бар» получит поведение «статический» по наследству.

1

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

0

Наследование необходимо для подтипирования. Рассмотрим:

class Base { 
    void Foo() { /* ... */ } 
    void Bar() { /* ... */ } 
} 

class Composed { 
    void Foo() { mBase.Foo(); } 
    void Bar() { mBase.Foo(); } 
    private Base mBase; 
} 

Даже если Composed поддерживает все методы Foo не могут быть переданы в функцию, которая рассчитывает значение типа Foo:

void TakeBase(Base b) { /* ... */ } 

TakeBase(new Composed()); // ERROR 

Итак, если вы хотите полиморфизм, вам нужно наследование (или его реализация интерфейса кузена).

Смежные вопросы