Объективно Хорошие Принципы проектирования OO

StackOverflow https://stackoverflow.com/questions/366719

  •  21-08-2019
  •  | 
  •  

Вопрос

Предпосылка

Я верю, что есть способ объективно определить "Хорошие" и "Плохие" методы объектно-ориентированного проектирования и что как сообщество мы можем определить, что это такое.Это академическое упражнение.Я верю, что если это будет сделано со всей серьезностью и решимостью, то это может принести большую пользу сообществу в целом.Сообщество выиграет от того, что у нас будет место, на которое мы все сможем указать, чтобы сказать: "Этот метод "Хорош" или "Плох", и мы должны или не должны использовать его, если не возникнут особые обстоятельства".

План

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

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

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

Основа

Я бы хотел попробовать определить понятия "Хороший" и "Плохой".:

  • "Хорошо" - Этот метод сработает с первого раза и станет долговременным решением.Позже его будет легко изменить, и временные затраты на его внедрение быстро окупятся.Он может быть последовательно применен и легко распознан программистами по техническому обслуживанию в будущем.В целом, это способствует хорошему функционированию и снижает затраты на техническое обслуживание в течение всего срока службы изделия.

  • "Плохо" - Этот прием может сработать в краткосрочной перспективе, но вскоре становится помехой.Это сразу трудно изменить или становится еще труднее с течением времени.Первоначальные инвестиции могут быть небольшими или крупными, но они быстро перерастают в растущие затраты, в конечном итоге превращаясь в невозвратные, и их необходимо постоянно устранять или обходить.Он применяется субъективно и непоследовательно и в будущем может стать неожиданным или нелегко распознаваемым программистами по техническому обслуживанию.В целом, это способствует конечному увеличению затрат на техническое обслуживание и / или эксплуатацию продукта и препятствует внесению изменений в продукт.Подавляя или предотвращая изменения, они становятся не просто прямыми издержками, но альтернативными издержками и значительной ответственностью.

Стартер

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

Разделение интересов

[Краткое описание]

Пример

[Код или какой-либо другой пример]

Цели

[Объяснение того, какие проблемы предотвращает этот принцип]

Применимость

[Почему, где и когда я буду использовать этот принцип?]

Исключения

[Когда бы я не стал использовать этот принцип, или где он действительно может быть вредным?]

Возражения

[Обратите внимание на любые особые мнения или возражения сообщества здесь]

Это было полезно?

Решение

Разделение интересов

Предпочитаю агрегацию наследованию в стиле Mixin

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

Пример (Boost.Не подлежит копированию):

Boost.Noncopyable - это класс C ++, в котором отсутствует конструктор копирования или оператор присваивания.Он может использоваться как базовый класс, чтобы предотвратить копирование или назначение подкласса (это обычное поведение).Он также может быть использован в качестве прямого участника

Преобразуйте это:

class Foo : private boost::noncopyable { ... };

К этому:

class Foo {
    ...
private:
    boost::noncopyable noncopyable_;
};

Пример (Блокируемый объект):

Java представила synchronized ключевое слово как идиома, позволяющая использовать любой объект потокобезопасным способом.Это может быть отражено в других языках для предоставления мьютексов произвольным объектам.Распространенным примером являются структуры данных:

class ThreadsafeVector<T> : public Vector<T>, public Mutex { ... };

Вместо этого эти два класса могли бы быть объединены вместе.

struct ThreadsafeVector<T> {
    Vector<T> vector;
    Mutex mutex;
}

Цели

Наследованием часто злоупотребляют как механизмом повторного использования кода.Если наследование используется для чего-либо, кроме отношения Is-A, общая ясность кода снижается.

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

Применимость

Любой язык, поддерживающий множественное наследование.

Исключения

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

Возражения

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

Другие советы

Есть несколько хорошо понятных принципов, которые могли бы стать хорошей отправной точкой:

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

Я думаю, короткий ответ заключается в том, что "хорошие" проекты OO устойчивы к изменениям, с наименьшей поломкой кода при любом изменении требований.Если вы рассмотрите все обычные правила, то все они приводят к одному и тому же выводу.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top