Я задал мне этот вопрос неоднократно при создании классов, особенно те, которые включают наборы, но я никогда не придумывал удовлетворительный ответ. Это - вопрос о дизайне ООП.
Например, в программе регистра чековой книжки говорят, что у меня есть класс BankAccount
. BankAccounts содержат данные, включающие Название учетной записи, Тип учетной записи (перечисление Проверки, Сохранения...), и другие данные, но самое главное набор Adjustment
s (депозиты или отказы) в учетной записи.
Здесь, у меня есть две опции для хранения набора Корректировок:
Я думаю, что оба решения интуитивны, и, конечно, оба предложения некоторые преимущества и недостатки. Например, инстанцирование позволяет класс (на языках, которые позволяют только единственный базовый класс) наследоваться другому классу, в то время как наследование от набора помогает управлять Добавлением, Удалите, и другие методы, не имея необходимость писать суррогатные методы, чтобы 'перенести' их.
Так, в таких ситуациях, который является лучшим подходом?
Для меня банковский счет имеет набор корректировок. Банковский счет не является набором корректировок, потому что он "является" гораздо большим, чем это: он также "является" именем, типом и т. д.
Так что в вашем случае (и подобных случаях), я предлагаю вам агрегировать коллекцию внутри вашего класса.
В случае сомнений, избегайте наследования. :-)
Я могу аргументировать это дальше. Чтобы правильно использовать наследование, подкласс должен удовлетворять принципу замещения Лискова; это означает, что в вашем случае BankAccount
должен быть допустимым типом везде, где ожидается Collection
. Я не думаю, что это так, потому что Collection
, вероятно, раскрывает такие методы, как Add()
и Remove()
, тогда как вы захотите установить определенный контроль над добавлением и удалением корректировок с вашего банковского счета, а не позволять людям добавлять и удалять их свободно.
Я думаю, что чрезмерное увлечение семантикой типа "это больше - это или есть" немного опасно - в конце концов, важно то, насколько хорошо ваш дизайн решил проблему, насколько легко поддерживать это и т. д. На самом деле, для меня поворотным моментом в моем понимании объектно-ориентированного программирования стал отказ от «объектов как существительных». Когда вы дойдете до объекта, это абстракция на один уровень выше функции, не более или менее.
Это был долгий способ сказать «имеет». :-) Создание подклассов сложно, использовать легко.
Лично я бы сказал, что BankAccount
имеет коллекцию Adjustment
. Возможно, у него будут и другие свойства, не относящиеся исключительно к тому, что было внесено или снято (клиент, тип банковского счета и т. д.).
С точки зрения дизайна, мой объект BankAccount
будет выставлять свойство типа Adjustments
с поздней загрузкой.
С точки зрения использования в коде, я бы инстанцировал банковский счет, и если бы мне нужно было узнать, что поступило и что выбыло со счета, я бы использовал открытое свойство. BankAccount был бы первичным объектом, ответственным за предоставление корректировок, относящихся только к инстанцированному счету.
Инстанцировать, определенно.
Я согласен с другими плакатами о том, что банковский счет - это "больше", чем просто набор других предметов. Или, может быть, вы просто выбрали пример, который действительно кричит о "инстанцировании".
Примеры: