Доступ к объектным методам с помощью композиции?
Это, вероятно, очень простая вещь, но я просто не могу разобраться в этом самостоятельно. При использовании композиции, каков лучший способ получить доступ к методам " внутреннего объекта?"Каждый способ, который я могу разработать, кажется, нарушает тот или иной принцип ОО.
Это своего рода очень широкая тема, но я приведу пример, чтобы сделать вещи ясными, насколько это возможно. Код написан на java, но я считаю, что этот вопрос применим практически к любому языку, использующему ООП.Class Shelf {
private Book book;
}
Class Book {
public void turnPage() {
//do stuff
}
}
Что будет ли лучшим способом получить доступ к методам книги, когда у вас есть только доступ к объекту полки? Несколько мест, которые я читал, предлагают методы обертывания внутри полки, так как это следует закону Деметры. Однако это не кажется лучшим вариантом для каждого случая.
Во-первых, многие методы внутреннего объекта могут не иметь ничего общего с главным классом, поэтому нет никакого смысла иметь главный класс, реализующий оболочки для каждого метода, и это, скорее всего, сломает единственный метод. Принцип Ответственности. Кроме того, если бы внутренний объект использовался для композиции в большом количестве других классов, все они должны были бы делать то же самое, это привело бы к большому количеству ненужного дублирования кода, делая ваш код гораздо менее сухим.
Мой первый инстинкт состоял в том, чтобы иметь простой метод getBook (), чтобы дать доступ к книге для непосредственного использования методов. Более разумно взять книгу с полки и перевернуть страницу, а не приказывать полке перевернуть страницу своей книги для вас. Однако это, по-видимому, нарушает как инкапсуляцию, так и закон Деметры. То же самое относится и к тому, чтобы сделать книгу "переменная" общедоступной.Я что-то упустил? Или все усложняет? Я, кажется, не могу поверить в это, так что я был бы очень признателен за помощь.
1 ответ:
В этом случае, скорее всего, у вас будут книги, а не одна книга на полке. Для меня имеет смысл вернуть конкретную книгу по идентификатору, который является уникальным для полки, и оперировать ею.
В этом случае я бы не стал возвращать коллекцию книг, которая затем нарушит инкапсуляцию и закон Деметры.Так, например:
public class Shelf { private Map<Long, Book> books = new HashMap(); // Class Code public Book getBook(Long id) { return books.get(id); } }
Что-то вроде этого не нарушает инкапсуляцию, потому что вы не раскрываете внутренние компоненты класса. Если ты когда-нибудь захочешь чтобы использовать список вместо карты, изменения не должны затрагивать ничего за пределами класса.
И в этом случае имеет смысл вернуть книгу, а не создавать методturnPage()
в классеShelf
. Это то же самое, как если бы у вас было свойствоname
вBook
, которое имеет тип string. Вы же не создадите методnameSubstring()
вBook
только для того, чтобы оперироватьname
, верно? Так зачем же создаватьturnPage()
в shelf только для того, чтобы оперироватьBook
?