Шаблон проектирования для постепенного «заполнения» объекта (вопрос начинающего) - PullRequest
2 голосов
/ 28 апреля 2011

Мне нужно обработать кучу данных - каждый элемент (элемент данных?) По сути является просто словарем текстовых атрибутов. Скажем, урок - «Книга» - у него могут быть автор, название, жанр, уровень сложности чтения и рекомендуемая цена. Теперь я начинаю, зная только первые два, и для каждой книги нужно сделать вывод или оценить следующие три (в моей проблеме это больше, чем это). Поэтому естественный для меня подход состоит в том, чтобы делать это итеративно для каждой книги. Мой дизайн будет выглядеть примерно так (это на Java)

public class Book
{
    public String author;
    public String title;
    /* ... */
    public double price;
    public Book(String author,String title)
    {
        this.author = author;
        this.title = title;
    }

    public void setGenre(DataProvider dp,...)
    {
        /* some sort of guess, resulting in genreGuess */
        this.genre = genreGuess;
    }

    /* .. and so on for price, etc */
}

А потом мой код хотел бы:

for (Book book : bookList)
{ 
    setGenre(book);
    setPrice(book);
    /* and so on */
}

Однако я пытаюсь научиться проектировать программы лучше, менее итеративно, используя менее изменяемое состояние. Кто-нибудь есть какие-либо рекомендации о том, как я мог бы пойти по этому поводу?

Ответы [ 3 ]

1 голос
/ 28 апреля 2011

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

Однако в реальных системах происходит то, что ваш АвторКласс, например, будет связью с Персоном и Контрактом, или Книга будет иметь Издателя.В библиотеке она может иметь историю того, когда она была приобретена, когда она была взята в аренду и возвращена, и что-то вроде записей ISBN и Библиотеки Конгресса.

За объектами было бы какое-то постоянное хранилище -- от чего-то такого простого, как «травление» в Python, до реляционной базы данных или хранилища таблиц «NoSQL».

Вот где начинает проявляться сложность.

Итак, вот некоторые вещи, которые нужноподумайте:

  • сколько объектов вы хотите хранить?Решения для 10 книг сильно отличаются от того, что вам нужно хранить 10 млн.

  • Если у вас сложное дерево объектов - с записями издателя, автора, персоны, контракта, LC,инвентаризация и т. д. - тогда создание (или «повторное увлажнение») объекта из .persistent store может занять много времени.Когда OO впервые завоевал популярность, это была традиционная проблема для первых систем: объектная модель была замечательной, но потребовалось полчаса, чтобы загрузить объект и все связанные с ним объекты.

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

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

    Лучший способ справиться с этим, в основном, написать код ,Напишите, нарисуйте, набросайте реальные примеры кода, используя ваши объекты, и посмотрите, просты ли они в использовании.

  • Как говорит Фред Брукс, «планируйте выбросить один, вы все равно будете».Как и при написании прозы, при написании кода переписывается.

1 голос
/ 28 апреля 2011

Я НЕ гуру OO-дизайна ... Вот один способ, который я лично считаю лучше.

Внедрите реализацию интерфейса GenreGuesser в Book ... это лучше всего сделать через BookFactory. Фабрика настраивается ОДИН РАЗ, а затем используется для создания «похожих» книг. Я подумываю об использовании здесь внедрения зависимостей (например, среды Springs DI или Google Guice), которая значительно сокращает накладные расходы по «подключению» фабрик к вещам, которые от них зависят; -)

Затем мы можем получить И КЕШИТЬ вычисленный атрибут на лету. Обратите внимание, что кэширование результата подразумевает, что IDENTITY объектов Book (например, author & title) является окончательным или, по крайней мере, фиксированным однократным набором.

public String getGenre()
{
  if (this.genre==null) 
    this.genre = genreGuesser.getGuess();
  return this.genre;
}

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

Это обеспечивает простой "богатый" интерфейс в классе Book; ценой того, чтобы сделать Книгу осведомленной о понятии "догадки" ... и я не фанат "интеллектуальных" объектов переноса, как таковых, что напоминает другой подход.

Если мы собираемся принять на себя все накладные расходы, связанные с наличием класса BookFactory, и мы МОЖЕМ ограничиться ТОЛЬКО КОГДА-ЛИБО созданием книг через фабрику, то почему бы просто не позволить BookFactory (который по определению знает все о Book и это атрибуты) заполнить все вычисляемые поля с (угаданными) значениями по умолчанию. Затем класс Book снова становится простым, тупым, передающим объектом, который делает именно то, что ему нужно, и НИЧЕГО ЕЩЕ.

Мне будет интересно прочитать предложения других.

Приветствия. Кит.

0 голосов
/ 28 апреля 2011

Первое, что я заметил, - setGenre и setPrice - методы-члены объекта Book.В этом случае вам не следует передавать книгу, а звонить

book.setGenre();
book.setPrice();

Но я не уверен, что вам следует это делать.Если вы пытаетесь сделать вывод о жанре и сложности и, в конечном итоге, о цене от автора и названия, вам не следует явно вызывать setGenre ().

Вместо этого вы можете вызвать

book.getPrice();

или

book.calculatePrice();

Тогда этот метод может определить пол и сложность, прежде чем вернуть окончательную цену.

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