Когда использовать наследование? - PullRequest
4 голосов
/ 21 января 2009

У меня и моего друга была небольшая дискуссия. Мне пришлось реализовать класс «наблюдатель процесса браузера», который вызывает событие всякий раз, когда просматриваемый браузер (скажем, Internet Explorer) работает.

Мы создали класс «Наблюдатель за процессами», и здесь начинается дискуссия:

Он сказал, что конструктор должен принимать только строки (например, «iexplore.exe»), и я сказал, что мы должны унаследовать «Process watcher», чтобы создать «обозреватель обозревателя», который принимает используемый в настоящее время обозреватель, перечисление «перевести» на «iexplore». он сказал, что мы должны использовать функцию util, которая будет выполнять роль переводчика.

Я знаю, что оба способа верны и хороши, но мне интересно, каковы плюсы и минусы каждого из них и что подходит в нашем случае.

Ответы [ 6 ]

11 голосов
/ 21 января 2009

В последнее время я придерживался подхода: «Будьте проще сейчас, а потом рефакторинг, если вам нужно его расширить».

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

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

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

6 голосов
/ 21 января 2009

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

Наследование подходит, когда вы хотите изменить поведение : если наблюдатель браузера будет делать то, чего не делает обычный наблюдатель процесса. Но если вы хотите изменить только значение data , просто измените данные.

4 голосов
/ 21 января 2009

Если у вас нет другого использования ProcessWatcher, кроме как в качестве родителя BrowserWatcher, вам не следует его создавать. Если реализуются другие наблюдатели, которые имеют общие функциональные возможности, которые могут быть размещены в ProcessWatcher, то вам следует (оба являются отношениями "isa", поэтому критерий Роба удовлетворяется).

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

2 голосов
/ 21 января 2009

Наследование должно использоваться только для реализации отношений "isa".

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

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

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

Итак, у нас есть класс Horse, обеспечивающий «ржание» для своего звука, класс Dog, обеспечивающий «лай» для его звука и т. Д.

НТН

ура

Rob

1 голос
/ 21 января 2009

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

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

0 голосов
/ 21 января 2009

Я согласен, что в большинстве случаев простота, а не сложность - это хорошая стратегия, если ваша простота не слишком близорука (см. Хермс, напишите код таким образом, чтобы его можно было легко переформулировать позже).

Тем не менее, я также знаю, как трудно скрыть эту ошибку в вашем ухе, которая поощряет более тщательный дизайн. Если вы все еще хотите отдать предпочтение наследованию без необходимости думать с точки зрения «базового класса» и «подкласса», вы можете просто определить интерфейс (например, IProcessWatcher), который реализуется ProcessWatcher. Когда вы используете объект ProcessWatcher, обращайтесь к нему в терминах интерфейса, чтобы, если позже вы решите создать BrowserWatcher (или любой другой тип ProcessWatcher), вы можете сделать это, не заставляя его спускаться с ProcessWatcher, пока реализует интерфейс IProcessWatcher.

Предупреждение: Действуйте с осторожностью. Становится заманчивым желание определить интерфейс для каждого отдельного объекта, и давайте посмотрим правде в глаза, это просто смешно. =)

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

Удачи!

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