Это всегда борьба за меня - могу ли я бросить вызов правильному объектно-ориентированному дизайну (например, вариант 1) или я использую реализацию, которая кажется противоречащей действительности (например, вариант 2)?
Реальность может быть хорошей отправной точкой для разработки или развития дизайна, но всегда ошибочно моделировать ОО дизайн в реальности.
ОО проектирование об интерфейсах, объектах, которые их реализуют, и взаимодействии между этими объектами (сообщениями, которые они передают между ними). Интерфейсы - это договорные соглашения между двумя компонентами, модулями или программными подсистемами. В ОО-дизайне есть много качеств, но самое важное для меня - это замена. Если у меня есть интерфейс, тогда код реализации лучше его придерживается. Но что более важно, если реализация поменялась местами, то новая реализация будет лучше придерживаться этого. Наконец, если реализация должна быть полиморфной, то лучше придерживаться ее в различных стратегиях и состояниях полиморфной реализации.
Пример 1
В математике квадрат является прямоугольником. Похоже, хорошая идея унаследовать класс Square от класса Rectangle. Вы делаете это, и это приводит к гибели. Зачем? Потому что ожидание или убеждение клиента было нарушено. Ширина и высота могут варьироваться независимо, но Square нарушает этот контракт. У меня был прямоугольник измерения (10, 10), и я установил ширину 20. Теперь я думаю У меня есть прямоугольник измерения (20, 10), но фактический экземпляр - это квадратный экземпляр с размерами ( 20, 20) и я, клиент, ожидаю настоящего большого сюрприза. Так что теперь у нас есть нарушение Принципа Наименьшего Сюрприза.
Теперь у вас есть ошибочное поведение, которое приводит к усложнению клиентского кода, как будто необходимы операторы для обхода ошибочного поведения. Вы также можете найти свой клиентский код, требующий RTTI, чтобы обойти ошибочное поведение, протестировав конкретные типы (у меня есть ссылка на Rectange, но я должен проверить, действительно ли это экземпляр Square).
Пример 2
В реальной жизни животные могут быть плотоядными или травоядными животными. В реальной жизни мясо и овощи - это виды пищи. Таким образом, вы можете подумать, что было бы неплохо иметь класс Animal в качестве родительского класса для разных типов животных. Вы также думаете, что было бы неплохо иметь родительский класс FoodType для класса Meat и класса Vegetable. Наконец, у вас есть в классе Animal sport метод eat (), , который принимает FoodType в качестве формального аргумента.
Все компилируется, проходит статический анализ и ссылки. Вы запускаете свою программу. Что происходит во время выполнения, когда подтип Animal, скажем, травоядный, получает FoodType, который является экземпляром класса Meat? Добро пожаловать в мир ковариации и контравариации. Это проблема для многих языков программирования. Это также интересная и сложная проблема для языковых дизайнеров.
В заключение ...
Так что ты делаешь? Вы начинаете с вашей проблемной области, ваших пользовательских историй, ваших вариантов использования и ваших требований. Пусть они управляют дизайном. Позвольте им помочь вам обнаружить сущности, которые вам нужно моделировать в классы и интерфейсы. Когда вы это сделаете, вы обнаружите, что конечный результат не основан на реальности.
Выезд Анализ образцов Мартина Фаулера. Там вы увидите, что движет его объектно-ориентированным дизайном. В основном это зависит от того, как его клиенты (медицинские работники, финансовые люди и т. Д.) Выполняют свои повседневные задачи. Оно пересекается с реальностью, но не основано и не обусловлено действительностью.