2013-08-28 2 views
1

У меня есть Configurator класса, для того, чтобы сделать свою работу, должны получать Context объект через интерфейс:Как использовать композицию вместо наследования?

public class Configurator : IContextAware 
{ 
    private IContext _context; 

    //property setter defined by the IContextAware interface 
    public IContext Context { set { _context = value; } } 

    // use _context object in other methods here ... 
} 

я планирую писать МНОГО Configurator типов, которые будут все необходимых для инициализации их _context полей так же. Моя первая мысль была «Почему не гнев каждого программиста в Интернете и использование наследования»?

public class ContextInitializer: IContextAware 
{ 
    // field to hold the injected context 
    protected IContext _context; 

    //property setter defined by the IContextAware interface 
    public IContext Context { set { _context = value; } } 
} 

public class Configurator : ContextInitializer 
{ 
    // use _context object here ... 
} 

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

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

Минусы: Наследование реализации есть зло, .. гм, Конфигуратор не может наследовать от любого другого класса .. ??

Я должен уточнить, что так или иначе Конфигуратор должен реализовывать интерфейс IContextAware. ТАКЖЕ, класс должен иметь конструктор по умолчанию/no-arg, поэтому инъекция зависимостей конструктора здесь не вариант.

Может ли кто-нибудь предложить, как можно использовать композицию для достижения тех же преимуществ, но с более гибким дизайном и/или описать реальные недостатки решения наследования выше? Благодаря!

P.S. Это адаптировано для Spring.Net CodeConfig, если кому-то интересно.

+0

Наследование - это зло? Я пропустил эту записку. – Rik

+0

@Rik http://blogs.msdn.com/b/steverowe/archive/2008/04/28/prefer-composition-over-inheritance.aspx http://www.javaworld.com/javaworld/jw-08- 2003/jw-0801-toolbox.html http://c2.com/cgi/wiki?ImplementationInheritanceIsEvil По правде говоря, если бы меня спросили: «Является ли' Configurator' 'ContextInitializer'? Я должен был бы сказать« нет », но ИСПОЛЬЗУЕТ' ContextInitalizer', тем самым предлагая наследование, не совсем здесь. – AFischbein

+1

Абсолютные утверждения * всегда * неправильные. Наследование не является по своей сути злым. Это инструмент. Вы можете использовать молоток, чтобы положить гвоздь в стену или взломать кого-то череп Это то, как вы его используете, это может быть зло. – Corak

ответ

1

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

Авторы BCL, очевидно, очень строги, когда речь заходит о дизайне API. Я никогда не видел такой огромной, но девственной коллекции типов.

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

Мой выбор: Я бы использовал ваш подход для внутреннего кода. Для общедоступных API (подумайте о библиотеках Codeplex и т. Д.) Я предпочел бы дублировать избыточные данные и поддерживать прозрачность публичного API.

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