Пример странного ООП
От: sobakam  
Дата: 23.07.12 09:24
Оценка:
Приветствую!
Лазил по форуму, наткнулся на закрытую тему...
http://www.rsdn.ru/forum/java/3945199.flat.2.aspx

В самам конце приведен код, есть вопрос, но туда добавить не смог, прошу не пинать ногами.
Сам столкнулся с подобной задачей, прошу помощи...
Код привожу чужой:

От:     Other Sam     
Дата:     03.09.10 12:44
    Оценка:    7 (1) +1
...
SD>Определить иерархию цветов. Создать несколько объектов-цветов. Собрать букет с определением его стоимости.
 ... поскипано ...

 В такой постановке задача не имеет сколько нибудь обоснованного решения.
 Вот примерное решение с разъяснением на какие грабли наступаем, и какие обходим.
// 1. Я решил запихать все что можно в абстрактный базовый класс
// чтобы код конкретных цветочков был как можно короче.
// 2. Хотя нет абстрактных методов, все равно класс помечен как абстрактный,
// чтобы никто не подумал добавлять неконкретный цветочек в букет.
public abstract class Flower {
    private final String name;
    private final BigDecimal price; // Деньги это не вещественные цисла. Поэтому для их подсчета
                                    // нужно всегда использовать какой-то целочисленный тип.

    protected Flower(String name, BigDecimal price) {
        this.name = name;
        this.price = price;
    }

    // 3. Общие методы для всех цветочков перенесены сюда.
    // (чтобы не дублировать в каждом цветочке)
    public String getName() {
        return name;
    }

    // 4. А вот этот метод относится не к цветочку, а к товару!!!
    // Здесь у нас произошло смешивание понятий. Цена это атрибут товара
    // а не растения!!! Но поскольку смешались оставим пока так.
    public BigDecimal getPrice() {
        return price;
    }
}

public class Rose extends Flower {
  // 5. собственно конкретный класс цветов
  public Rose() {
    super("Rose", BigDecimal.valueOf(5.22).setScale(2, RoundingMode.HALF_EVEN));
  }
}

public class Tulip extends Flower {
  public Tulip() {
    // Реально при работе с деньгами я видел две стратегии.
    // Использовать рубли/копейки (т.е. 2 знака после запятой)
    // или использовать 4 цифры после запятой.
    // Здесь я использую 2 цифры после запятой.
    // Кстати это является потенциально опасным местом
    // В коде закодированно вещественное число 1.27, которое затем округляется
    // до целочисленного 1.27
    // По идее точнее было-бы
    // BigDecimal.valueOf(127).divide(BigDecimal.valueOf(100), RoundingMode.HALF_EVEN)
    //   .setScale(2, RoundingMode.HALF_EVEN)
    // Но такой код очень сложно читать. Так что я через float задал.
    super("Tulip", BigDecimal.valueOf(1.27).setScale(2, RoundingMode.HALF_EVEN));
  }
}

// 6. Собственно класс букетика.
// Поскольку нужно "собрать" букет и посчитать его цену
// появляются две обязанности "собрать букет" "посчитать цену"
// Эти обязанности нельзя возлагать на классы цветочков. (Это определяется анализом)
// Следовательно новый класс для "собрать букет".
// Собирание букета сильно похоже на использование коллекций - поэтому
// будем пользоваться уже готовой коллекцией.
// Но чтобы в готовую коллекцию добавить еще одну ответственность -
// "посчет стоимости".
// Так и сделаем - добавим метод.
public class FlowerPack extends ArrayList<Flower> {
  public BigDecimal getPackPrice() {
    BigDecimal summ = BigDecimal.ZERO;
    for (Flower f : this) {
      summ = summ.add(f.getPrice());
    }
    return summ;
  }
}

public void testBuket() {
    FlowerPack pack = new FlowerPack();
    pack.add(new Rose());
    pack.add(new Rose());
    pack.add(new Tulip());
    System.out.println(pack.getPackPrice());
}


возникает интересный вопрос...
Что будет с нашим букетом. если там 20 одинаковых роз...
Разве целесообразно будет в лист напихивать 20 объектов? Есть мысль напихивать объекты цветов, чтобы добавлялся не сам объект, а попутно с количеством. Но само количество по моему не должно быть атрибутом объекта цветка....
Прошу подсказать идею по букету
Re: Пример странного ООП
От: Kswapd Россия  
Дата: 23.07.12 09:29
Оценка:
Есть идея: http://en.wikipedia.org/wiki/Flyweight_pattern
Re: Пример странного ООП
От: Blazkowicz Россия  
Дата: 23.07.12 09:34
Оценка: +2
Здравствуйте, sobakam, Вы писали:

S>Что будет с нашим букетом. если там 20 одинаковых роз...

Что будет?

S>Разве целесообразно будет в лист напихивать 20 объектов?

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

S>Есть мысль напихивать объекты цветов, чтобы добавлялся не сам объект, а попутно с количеством. Но само количество по моему не должно быть атрибутом объекта цветка....

Если клиенту не нужно различать отдельные цветки, то да. А если это модель какой-нибудь выставки, где каждый лепесток на учете. То нет.

S>Прошу подсказать идею по букету

Это просто разминка по ООП. Когда будет конкретная цель, тогда будут конкретные решения. Но направление мысли у вас верное.
Re[2]: Пример странного ООП
От: sobakam  
Дата: 23.07.12 11:29
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, sobakam, Вы писали:


S>>Что будет с нашим букетом. если там 20 одинаковых роз...

B>Что будет?

S>>Разве целесообразно будет в лист напихивать 20 объектов?

B>Зависит от решаемой задачи. Если накладную заполнять для оптового магазина, то, наверное не имеет.
B>А если каждую розу наделить уникальным значением атрибутов, то почему нет. Но мысль верная.

S>>Есть мысль напихивать объекты цветов, чтобы добавлялся не сам объект, а попутно с количеством. Но само количество по моему не должно быть атрибутом объекта цветка....

B>Если клиенту не нужно различать отдельные цветки, то да. А если это модель какой-нибудь выставки, где каждый лепесток на учете. То нет.

S>>Прошу подсказать идею по букету

B>Это просто разминка по ООП. Когда будет конкретная цель, тогда будут конкретные решения. Но направление мысли у вас верное.

Конечно, есть моменты, но, в любом случае, букет навряд ли будет состоять из всех оригинальных цветов Думаю найти подходящий способ хранения... Хочется просто так сделать, чтобы самому понравилось... Вообще такая задача применима к хранению объектов вообще, даже не в букете собственно дело, просто я , как начинающий изучение Java, наткнулся на тот букет и задался вопросом, как бы сделал я.
Re[2]: Пример странного ООП
От: Аноним  
Дата: 23.07.12 11:30
Оценка:
Здравствуйте, Kswapd, Вы писали:

K>Есть идея: http://en.wikipedia.org/wiki/Flyweight_pattern


Благодарю, сейчас посмотрю
Re[3]: Пример странного ООП
От: Blazkowicz Россия  
Дата: 23.07.12 11:37
Оценка:
Здравствуйте, sobakam, Вы писали:

S>Конечно, есть моменты, но, в любом случае, букет навряд ли будет состоять из всех оригинальных цветов

Букет вряд ли состоит из всех полностью идентичных цветков.

S>Думаю найти подходящий способ хранения...

Это не "хранение". Это дизайн модели предметной области. И моделью оно называется, потому что задача не создать модель ради модели, а создать модель ради конретного решения. У продавца модель одна, у флориста — другая, у ботаника — третья. Хотя все оперируют одними и теми же цветами.

S>Хочется просто так сделать, чтобы самому понравилось...

Решайте все же конкретную проблему. Хотя если самому понравиться, то, конечно, мотивация будет выше.

S>Вообще такая задача применима к хранению объектов вообще, даже не в букете собственно дело, просто я , как начинающий изучение Java, наткнулся на тот букет и задался вопросом, как бы сделал я.

Гуглите про "моделирование предметной области". Разные модели решают разные задачи. Если вы создадите какую-нибудь модель, то к ней всегда найдется задача, в которой эта модель будет плохо работать.
Re[4]: Пример странного ООП
От: sobakam  
Дата: 23.07.12 11:51
Оценка:
Я хочу ограничиться конечно в рамках данной узкой задачи.
Атрибутов в классах будет не много, в принципе те что есть достаточны.
По большому счету роза, тюльпан, орхидея. На базе розы могу создать обьект чайная роза итд...
Я представил, допустим, таблицу в свинге. По большому счету так или иначе предоставить данные необходимо в наглядном виде. А подсчет количества одинаковых объектов-это, как ни крути, еще метод и дополнительные вычисления...
Я это дело просто уже набросал, буду искать подходящий вариант конструкции.
Вас спасибо за участие
Re[5]: Пример странного ООП
От: Mr.Delphist  
Дата: 23.07.12 12:28
Оценка:
Здравствуйте, sobakam, Вы писали:

S>Я хочу ограничиться конечно в рамках данной узкой задачи.

S>Атрибутов в классах будет не много, в принципе те что есть достаточны.
S>По большому счету роза, тюльпан, орхидея. На базе розы могу создать обьект чайная роза итд...
S>Я представил, допустим, таблицу в свинге. По большому счету так или иначе предоставить данные необходимо в наглядном виде. А подсчет количества одинаковых объектов-это, как ни крути, еще метод и дополнительные вычисления...
S>Я это дело просто уже набросал, буду искать подходящий вариант конструкции.
S>Вас спасибо за участие

Тогда нужен не массив из Flower, а карта (map), который бы ставил в соответствие
Rose — 1 000 000 штук
Tulip — 1 001 штука

Или как-то так. Тут верный вопрос ещё задали — а что за требования в предметной области? Ведь можно дать ситуацию, что в букете 5 роз белых, 3 розы красных, 1 розовая... Т.е. тогда в карту неявно въезжает ещё и атрибут "цвет" — а в ходит ли он в атрибуты самого Flower? Ну и т.п.

Возможно, потребуется дополнительный класс (или даже иерархия) "валидатор букета": что на похороны надо чётное число цветов, на иные мероприятия — нечетное, для торжественных случаев нужен сложный букет не менее N видов цветов плюс аксессуары (корзинки, бабочки, беджики с пожеланиями etc), каждому цветку можно сопоставить дату его сбора, и тогда в букете не должно быть цветов старше, чем допуск для данного вида (одни сорта вянут быстро, другие нет).

...etc...
Re[6]: Пример странного ООП
От: Аноним  
Дата: 23.07.12 13:17
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:


Благодарю за наводку, про map тоже счаз думал. Вообще по цвету, это будет атрибут конкретного объекта. То есть простая роза будет красная, чайная будет чайная, белая будет белая итд... Я так сделал чтобы особо не размахивать в иерархии. По сути название объекта будет отражать все свойства включая цвет. Набивать их буду скопом по очереди, как в том примере... Я задался именно вопросом чтобы не дублировать объекты, а хранить в классе букета их типа Объект-количество (одинаковых)... То есть при добавлении, скажем, в карту, проверять уникальность, ну и в случае нахождения такового в списке изменять количество. В противном случае-добавляем новый... Я правильно мыслю?
Re[7]: Пример странного ООП
От: Mr.Delphist  
Дата: 23.07.12 13:48
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Mr.Delphist, Вы писали:



А>Благодарю за наводку, про map тоже счаз думал. Вообще по цвету, это будет атрибут конкретного объекта. То есть простая роза будет красная, чайная будет чайная, белая будет белая итд... Я так сделал чтобы особо не размахивать в иерархии. По сути название объекта будет отражать все свойства включая цвет. Набивать их буду скопом по очереди, как в том примере... Я задался именно вопросом чтобы не дублировать объекты, а хранить в классе букета их типа Объект-количество (одинаковых)... То есть при добавлении, скажем, в карту, проверять уникальность, ну и в случае нахождения такового в списке изменять количество. В противном случае-добавляем новый... Я правильно мыслю?


Абсолютно.
Re: Пример странного ООП
От: Аноним  
Дата: 25.07.12 07:31
Оценка:
Здравствуйте, sobakam, Вы писали:

S>Приветствую!

S>Лазил по форуму, наткнулся на закрытую тему...
S>http://www.rsdn.ru/forum/java/3945199.flat.2.aspx

S>возникает интересный вопрос...

S>Что будет с нашим букетом. если там 20 одинаковых роз...
S>Разве целесообразно будет в лист напихивать 20 объектов? Есть мысль напихивать объекты цветов, чтобы добавлялся не сам объект, а попутно с количеством. Но само количество по моему не должно быть атрибутом объекта цветка....
S>Прошу подсказать идею по букету

1. Вам надо понять, что меняется от цветка к цветку. Поведение или состояние.
2. Нужно понять, возможны ли изменения поведения или состояния в рантайме или все известно на этапе компиляции.

Если у вас меняется поведение, например различные цветки будут расти с различной скоростью, либо в разных направлениях, то выделяете интерфейс, типа:

public interface Flowable
{
  void flow();
}


Теперь, надо определить как цветки имплментят ваш Flowable. Если поведение известно на этапе компиляции, то есть две опции — через наследование (не рекомендуется), через enum.
Скорее всего на этапе компиляции вы уже будете знать, какой цветок какую реализацию Flowable использует, значит, лучше реализовать цветок как enum, передав в констуркторе конкретную имплментацию Flowable. Если поведение нужно менять в runtime, добавляем сеттер.

Но поведение цветков скорее не меняется от цветка к цветку, у вас меняется цвет и, допустим, стоимость, т.е. состояние.
Цвет у цветков, допустим известен сразу, compile-time данные, а вот цена — хотелось бы передать в runtime.

Если хоть одно из изменений состояния или поведение нужно менять в runtime, отказываемся от enum (оч. люблю их). Делаем сеттеры для состояний либо через конструкторы. Парметр один — цена, лучше через конструктор с типом BidDecimal price

Т.е. все ваши цветки будут наследовать какой то AbstractFlower и будут отличаться лишь двумя состоянями:
1. цвет, его задаем через private static final String COLOR = "red"; — величина для класса всегда будет постоянная.
2. цена, передаем всегда в конструкторе

Опять же, вы можете рассмотреть каждый цветок — как результат аггрегации лепестков, корня, бутона и т.д. Это уже другая история, но направление, надеюсь, вам понятно
Хотелось бы услышать аргументированную критику.
Re: Пример странного ООП
От: andyag  
Дата: 29.07.12 11:14
Оценка:
Здравствуйте, sobakam, Вы писали:

S>Приветствую!

S>Лазил по форуму, наткнулся на закрытую тему...
S>http://www.rsdn.ru/forum/java/3945199.flat.2.aspx

...

S>возникает интересный вопрос...

S>Что будет с нашим букетом. если там 20 одинаковых роз...
S>Разве целесообразно будет в лист напихивать 20 объектов? Есть мысль напихивать объекты цветов, чтобы добавлялся не сам объект, а попутно с количеством. Но само количество по моему не должно быть атрибутом объекта цветка....
S>Прошу подсказать идею по букету

А какую задачу вы решаете? Для задачи "есть букет, нужно на странице отобразить его стоимость" достаточно вот такого мега-дизайна:
class BunchOfFlowers {
  public int totalPrice; // количество денег в копейках, например
}

BunchOfFlowers bunch = new BunchOfFlowers();
bunch.totalPrice = 100000; // 1000 рублей


Если у вас всё чуть детальнее и можно сконструировать букет по количествам цветов, то:
class Flower { // цветок имеет имя и стоимость (Роза, 150 рублей)
  public String name;
  public int price;
}

class BunchLine { // order line -> bunch line (лучше не придумалось)
  public Flower flower;
  public int numberOfItems;
}

class BunchOfFlowers { // букет состоит из нескольких наборов цветов, в каждом из которых цветы одинаковые
  public Collection<FlowerLine> flowerLines;
}

// это не цветок в смысле "вот этот конкретный цветок", а в смысле "вид цветка"
Flower rose = new Flower("Rose", 15000); // розы по стописят у нас
Flower tulip = new Flower("Tulip", 10000); // тюльпаны по сотне отдам

BunchLine roses = new BunchLine(rose, 13); // 13 розочек
BunchLine tulips = new BunchLine(tulip, 11); // 11 тюльпанчегов

BunchOfFlowers bunch = new BunchOfFlowers(Arrays.toList(toses, tulips));


Если ваш конструктор букетов настолько крут, что можно ещё и положение отдельных цветов в букете определять, будет что-то вроде:
class Flower {...} // Роза, 150 рублей

class PositionedFlower {
  public Flower flower; // Роза, 150 рублей
  public FlowerPosition position; // Посерединке
}

class BunchOfFlowers {
  public Collection<PositionedFlower> positionedFlowers;
}

Flower rose = new Flower("Rose", 15000);
Flower tulip = new Flower("Tulip", 10000);

BunchOfFlowers bunch = new BunchOfFlowers(Arrays.toList(
  new PositionedFlower(rose, FlowerPosition.Center),
  new PositionedFlower(rose, FlowerPosition.Left),
  new PositionedFlower(rose, FlowerPosition.Right)
));


В любом случае я не представляю ситуацию когда вам может понадобиться иерархия вроде Tulip implements Flower — это имеет смысл только в академических задачках и по глупости сравнимо с обсуждением наследования квадрата от прямоугольника.
Re: Пример странного ООП
От: ResidentR6  
Дата: 29.07.12 15:23
Оценка:
Объект — та хрень, которой предполагается дать инкапсуляцию,
наследование или полиморфизм. Если ничего из этого не надо, то и не
делайте объекта.

В данном случае, цветок — объект и представляет разные свойства: цена,
цвет, повод к которому подходит и т.п. Но при этом цветок не является
ТОВАРОМ! Цветок, как объект, не должен знать что он товар!!!

С точки зрения продавца товар — это товар. Имеющий вид и количество.
Примерно так:
class Сommodity{
private Class clazz;
private int quantity;
...
public Сommodity(class c){this.clazz=c;}
...
}

Соответсвено твой букет для продавца
Сommodity bunch = new Commodity(Rose.class);
bunch.setPrice...
bunch.setRebate...
bunch.setQuantity...


Конечно могут быть и другие варианты, но решение в плане ШАБЛОНА
однозначно — букеты и прочие счастья должны ВКЛЮЧАТЬ в себя объект
класса, без необходимости разбираться в деталях объекта если сие не
требуется.

ЗЫ. Тут правильно заметили: сначала моделируем реальность, а потом уже
кодим. Иначе непонятки логические зароются в код и скушают туеву хучу
времени. На реальной работе, когда узнают источник проблемы — будут бить
ногами, прямо на митинге.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Пример странного ООП
От: sobakam  
Дата: 05.08.12 19:52
Оценка:
Народ, всем огромное спасибо по советам.
Вообще задача стояла Определить иерархию цветов. Создать несколько объектов-цветов. Собрать букет с определением его стоимости...
То есть как ни крути иерархия должна быть...
Был сделан абстрактный класс, как из примера

public abstract class Flower {

    private final String name;          //Flower Name
    private final String color;         //Flower color
    private final BigDecimal price;     //Price of a single flower
    
    //Constructor with parameters
    protected Flower(String name,String color, BigDecimal price) {

        if ( price.signum() < 0) {
            throw new IllegalArgumentException("Price can not be less then zero.");
        }

        if (name == null) {
            throw new NullPointerException("Argument name can not be null.");
        }

        if (name.isEmpty()) {
            throw new IllegalArgumentException("Name of flower can not be empty.");
        }

        if (color == null) {
            throw new NullPointerException("Argument color can not be null.");
        }

        this.name = name;       //Set a Flower Name
        this.color = color;     //Set a Flower color
        this.price = price;     //Set the Price for one flower

    }

    
    public String getName() {

        return name;
    }

    public String getColor() {

        return color;
    }

    public BigDecimal getPrice() {

        return price;
    }
}


Потом я наполняю в коллекцию их


public class Bouquet extends HashMap <Flower, Integer> {
    protected String BouquetName;

    Bouquet(String BouquetName){

        this.BouquetName = BouquetName;
        System.out.println("\nNew Bouquet: "+BouquetName+"\n");

    }

    public BigDecimal getPackPrice() {

        BigDecimal sum = BigDecimal.ZERO;
        Iterator it= this.entrySet().iterator();
        while(it.hasNext()){

            Map.Entry <Flower, Integer> m = (Map.Entry)it.next();
            sum = sum.add(m.getKey().getPrice().multiply(BigDecimal.valueOf(m.getValue())));

        }

        String str = String.format("\nTotal Bouquet %1$15s price: %2$32s\n",BouquetName,sum);
        System.out.println (str);
        return sum;

    }

    // implemented method
    public Integer put(Flower key, Integer value) {

            Integer result = super.put(key, value);
            String s = String.format("Added flower: %1$8s\t,color: %2$8s\t, count: %3$2d, price: %4$5s", key.getName(),key.getColor(),value, key.getPrice());
            System.out.println(s);

        return result;

    }

}


Потом создаем сам букет итд


public class BouquetStore {

    public static void main(String[] args) {

        //Creates а new instance of the class Rose, object Tea Rose
        Flower TeaRose = new Rose("TeaRose","Tea", BigDecimal.valueOf(7.23).setScale(2, RoundingMode.HALF_EVEN));

        //Creates а new instance of the class Bouquet, object pack. This name is "Happy New Year"
        Bouquet pack = new Bouquet ("Happy New Year");
        pack.put(new Rose(),1);
        pack.put(TeaRose,2);
        pack.put(new Orchid(),2);
        pack.put(new Tulip(),1);
        pack.getPackPrice();

        //Create а new Bouquet   "Wedding"
        Bouquet pack1 = new Bouquet("Wedding");
        pack1.put(new Rose(),5);
        pack1.put(new Orchid(),2);
        pack1.put(new Tulip(),1);
        pack1.getPackPrice();

        //Create а new Bouquet   "Love Story"
        Bouquet pack2 = new Bouquet("Love Story");
        pack2.put(new Rose(),15);
        pack2.getPackPrice();

    }
}


Еще подскажите убогому, не пинайте ногами, кроме всего прочего вот это:

public class Bouquet extends HashMap <Flower, Integer> {
    protected String BouquetName;

То есть я имею в виду не будет ли это криво если я здесь добавляю поле BouquetName в класс при такой конструкции или
ИЛИ правильнее:

public class Bouquet 
        private Map <Flower, Integer> Pack = new HashMap <Flower, Integer>;
    protected String BouquetName;


Приветствую любую критику!
Re[3]: Пример странного ООП
От: Аноним  
Дата: 06.08.12 05:59
Оценка:
правильнее
S>
S>public class Bouquet 
S>        private Map <Flower, Integer> Pack = new HashMap <Flower, Integer>;
S>    protected String BouquetName;
S>


+ не надо забывать про name conventions:

public class Bouquet 
        private Map <Flower, Integer> pack = new HashMap <Flower, Integer>;
    protected String bouquetName;
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.