Проектирование модели данных
От: dorofeevilya Россия  
Дата: 25.07.07 07:05
Оценка:
Существует абстрактный базовый класс A :
class Generic_A
{
};


От него отнаследованы еще 4 класса:
class Derived_A1 : public Generic_A { ... };
class Derived_A2 : public Generic_A { ... };
class Derived_A3 : public Generic_A { ... };
class Derived_A4 : public Generic_A { ... };


Также существует класс B, который агрегирует в себе объект класса A (а точнее одного из его наследников):
class B
{
    Generic_A* a;
};


Но в связи с особенностями предметной области класс B может агрегировать только либо Derived_A1, либо Derived_A2, либо Derived_A3, но не Derived_A4. Также существует класс C:
class C
{
    Generic_A* a;
};


Он может агрегировать только либо Derived_A2, либо Derived_A3.

Как лучше смоделировать такую ситуацию?
Re: Проектирование модели данных
От: Mazay Россия  
Дата: 25.07.07 07:12
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>Как лучше смоделировать такую ситуацию?


Ну первое, что приходит в голову, это выделить два интерейса: SuitableForB и SuitableForC. Соответственно Derived_A1, Derived_A2 и Derived_A3 будут реализовывать SuitableForB, а Derived_A2 и Derived_A3 — SuitableForC.
Главное гармония ...
Re[2]: Проектирование модели данных
От: dorofeevilya Россия  
Дата: 25.07.07 07:18
Оценка:
Здравствуйте, Mazay, Вы писали:

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


D>>Как лучше смоделировать такую ситуацию?


M>Ну первое, что приходит в голову, это выделить два интерейса: SuitableForB и SuitableForC. Соответственно Derived_A1, Derived_A2 и Derived_A3 будут реализовывать SuitableForB, а Derived_A2 и Derived_A3 — SuitableForC.



Мне тоже пришла в голову такая идея, но не более того... Не могу представить, что должны из себя представлять интерфейсы SuitableFor*.
Re: Проектирование модели данных
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 25.07.07 07:19
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>Но в связи с особенностями предметной области класс B может агрегировать только либо Derived_A1, либо Derived_A2, либо Derived_A3, но не Derived_A4. Также существует класс C:

D>Он может агрегировать только либо Derived_A2, либо Derived_A3.

D>Как лучше смоделировать такую ситуацию?


Либо плотно подумать над общей архитектурой, либо рассказать, почему такое происходит (выборочная агрегация), либо ввести [маркерные] интерфейсы.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
HgLab: Mercurial Server and Repository Management for Windows
Re[2]: Проектирование модели данных
От: dorofeevilya Россия  
Дата: 25.07.07 07:36
Оценка:
Здравствуйте, Нахлобуч, Вы писали:

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


D>>Но в связи с особенностями предметной области класс B может агрегировать только либо Derived_A1, либо Derived_A2, либо Derived_A3, но не Derived_A4. Также существует класс C:

D>>Он может агрегировать только либо Derived_A2, либо Derived_A3.

D>>Как лучше смоделировать такую ситуацию?


Н>Либо плотно подумать над общей архитектурой, либо рассказать, почему такое происходит (выборочная агрегация), либо ввести [маркерные] интерфейсы.



Над общей архитектурой уже давно плотно думаю На этой проблеме застопорился.
Ситуация такова: необходима модель данных для описания конструкций многоэтажных зданий. Они состоят из отдельных конструктивных элементов: плит, колонн, балок и т. д. Каждый конструктивный элемент (классы B и C), понятно, сделан из какого-либо материала (класс Generic_A, а также унаследованные от него). На мой взгляд вполне логично представить Материал в виде абстракции (класс Generic_A), а затем уточнить его вид в конкретном классе с помощью наследования (классы Derived_A*). Однако, допустим, конструктивному элементу "Плита" могут быть назначены материалы Derived_A1, Derived_A2, Derived_A3, а элементу "Колонна" — Derived_A2 и Derived_A3.

А насчет "маркерных" интерфейсов я не в курсе
Re: Проектирование модели данных
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 25.07.07 08:01
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>Как лучше смоделировать такую ситуацию?

Если Вы используете полиморфное наследование, то объект любого производного класса может быть применен там, где может быть применен объект базового класса. Собственно, в этом и заключается LSP (принцип подстановки Барбары Лисков).

Если у Вас он не выполняется, значит что-то спроектировано неверно. В чем конкретно заключается "неверность", сказать трудно — нужны конкретные детали.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[2]: Проектирование модели данных
От: dorofeevilya Россия  
Дата: 25.07.07 08:08
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, dorofeevilya, Вы писали:


D>>Как лучше смоделировать такую ситуацию?

КЛ>Если Вы используете полиморфное наследование, то объект любого производного класса может быть применен там, где может быть применен объект базового класса. Собственно, в этом и заключается LSP (принцип подстановки Барбары Лисков).

КЛ>Если у Вас он не выполняется, значит что-то спроектировано неверно. В чем конкретно заключается "неверность", сказать трудно — нужны конкретные детали.



Детали:
Необходима модель данных для описания конструкций многоэтажных зданий. Они состоят из отдельных конструктивных элементов: плит, колонн, балок и т. д. Каждый конструктивный элемент (классы B и C), понятно, сделан из какого-либо материала (класс Generic_A, а также унаследованные от него). На мой взгляд вполне логично представить Материал в виде абстракции (класс Generic_A), а затем уточнить его вид в конкретном классе с помощью наследования (классы Derived_A*). Однако, допустим, конструктивному элементу "Плита" могут быть назначены материалы Derived_A1, Derived_A2, Derived_A3, а элементу "Колонна" — Derived_A2 и Derived_A3.
Re[3]: Проектирование модели данных
От: Mazay Россия  
Дата: 25.07.07 08:10
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>Мне тоже пришла в голову такая идея, но не более того... Не могу представить, что должны из себя представлять интерфейсы SuitableFor*.


По идее это должно зависеть от того, как классы B и C их используют. Если никак не используют, то могут быть пустыми. (Кажется, Нахлобуч именно такие интерфейсы и назвал "маркерными")
Главное гармония ...
Re[3]: Проектирование модели данных
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 25.07.07 08:10
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>Над общей архитектурой уже давно плотно думаю На этой проблеме застопорился.

Почему материал нельзя представить в виде идентификатора, а зависимость между изделием и материалом — в виде таблицы?
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[3]: Проектирование модели данных
От: Mazay Россия  
Дата: 25.07.07 08:18
Оценка: +1
Здравствуйте, dorofeevilya, Вы писали:

D>Детали:

D>Необходима модель данных для описания конструкций многоэтажных зданий. Они состоят из отдельных конструктивных элементов: плит, колонн, балок и т. д. Каждый конструктивный элемент (классы B и C), понятно, сделан из какого-либо материала (класс Generic_A, а также унаследованные от него). На мой взгляд вполне логично представить Материал в виде абстракции (класс Generic_A), а затем уточнить его вид в конкретном классе с помощью наследования (классы Derived_A*). Однако, допустим, конструктивному элементу "Плита" могут быть назначены материалы Derived_A1, Derived_A2, Derived_A3, а элементу "Колонна" — Derived_A2 и Derived_A3.

ИМХО не стоит задавать в коде материиалы, из которых могут быть сделаны конструктивные элементы. Тут вообще можно выделить только два класса — КонструктивныйЭлемент и Материал. Остальное — "типичная ошибка ООП".
Главное гармония ...
Re[4]: Проектирование модели данных
От: Mazay Россия  
Дата: 25.07.07 08:22
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, dorofeevilya, Вы писали:


D>>Над общей архитектурой уже давно плотно думаю На этой проблеме застопорился.

КЛ>Почему материал нельзя представить в виде идентификатора, а зависимость между изделием и материалом — в виде таблицы?

Зачем ввиде таблицы? Тут пока свзяи многие-ко-многим нет. Хотя напрашивается конечно.
Главное гармония ...
Re[4]: Проектирование модели данных
От: dorofeevilya Россия  
Дата: 25.07.07 08:29
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, dorofeevilya, Вы писали:


D>>Над общей архитектурой уже давно плотно думаю На этой проблеме застопорился.

КЛ>Почему материал нельзя представить в виде идентификатора, а зависимость между изделием и материалом — в виде таблицы?

А в чем разница? Так или иначе будет возможность назначить неподходящий материал элементу. Как я понимаю, здесь необходимо делать проверку типа материала при назначении его элементу. Вопрос, когда выполнять эту проверку: на этапе компиляции или во время выполнения. Во время выполнения можно сделать так:


class Material
{
    virtual MaterialType GetType() = 0;
};

class Material1 : public Material
{
     /* Поля класса*/

     virtual MaterialType GetType() { return MaterialType.Material1; }
};

class Material2 : public Material
{
     /* Поля класса*/

     virtual MaterialType GetType() { return MaterialType.Material2; }
};
// и т. д. для Material3 и Material4

class B
{
    private Generic_A* material;

    public  SetMaterial(Generic_A* m)
    {
        switch (m->GetType())
        {
            case MaterialType.Material1:
            case MaterialType.Material2:
            case MaterialType.Material3:
                material = m;
                break;

            default:
                throw();   // или что-то еще
        }         
    }
};


А реально ли предоставить эту проверку компилятору?
Re[4]: Проектирование модели данных
От: dorofeevilya Россия  
Дата: 25.07.07 08:30
Оценка:
Здравствуйте, Mazay, Вы писали:

M>ИМХО не стоит задавать в коде материиалы, из которых могут быть сделаны конструктивные элементы. Тут вообще можно выделить только два класса — КонструктивныйЭлемент и Материал. Остальное — "типичная ошибка ООП".



Не понял...
Re[5]: Проектирование модели данных
От: Mazay Россия  
Дата: 25.07.07 08:51
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>Здравствуйте, Кирилл Лебедев, Вы писали:


КЛ>>Здравствуйте, dorofeevilya, Вы писали:


D>>>Над общей архитектурой уже давно плотно думаю На этой проблеме застопорился.

КЛ>>Почему материал нельзя представить в виде идентификатора, а зависимость между изделием и материалом — в виде таблицы?

D>А в чем разница? Так или иначе будет возможность назначить неподходящий материал элементу. Как я понимаю, здесь необходимо делать проверку типа материала при назначении его элементу. Вопрос, когда выполнять эту проверку: на этапе компиляции или во время выполнения. Во время выполнения можно сделать так:


// страшный свич ы ужасе поскипан

D>А реально ли предоставить эту проверку компилятору?

Реально — через [маркерные] интерфейсы, но незачем. Лучше если это можно будет настраивать без изменения кода.

Посмотрев на этот код, понял о какой таблице говорил Кирил. Я думал о типичной разводке связи многие-ко-многим, а имелась ввиду таблица соответствия идентификатора элемента к списку допустимых для него материалов.
В коде у тебя должно быть что-то вроде такого мэпа:


map<ElementType, set<MaterialID> > allowedMaterials;



Тогда код будет такой:


void Element::setMaterial(Matetrial *material)
{
   if (allowedMaterials[this->getType()].contains(material->getId()))
   {
       this->setMaterial(material);
   } else // error!
}
Главное гармония ...
Re[5]: Проектирование модели данных
От: Mazay Россия  
Дата: 25.07.07 08:54
Оценка: +1
Здравствуйте, dorofeevilya, Вы писали:

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


M>>ИМХО не стоит задавать в коде материиалы, из которых могут быть сделаны конструктивные элементы. Тут вообще можно выделить только два класса — КонструктивныйЭлемент и Материал. Остальное — "типичная ошибка ООП".


D>Не понял...


Вот здесь
Автор: ferrata
Дата: 26.03.05
обсуждалось. Общая идея состоит в том, что не стоит пытаться делать класс на каждую сущность предметной области.
Главное гармония ...
Re[5]: Проектирование модели данных
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 25.07.07 09:04
Оценка: +1 :)
Здравствуйте, dorofeevilya, Вы писали:

D>А в чем разница? Так или иначе будет возможность назначить неподходящий материал элементу.

А зачем данные, которые, к тому же, могут еще и поменяться хардкодить в код? По последним данным известно около 7 млн. органических и 160 тыс. неорганических соединений естественного и искусственного происхождения. Согласитесь, неразумно каждое из них представлять в виде класса.

Поэтому конкретные данные должны содержаться в файле или в базе данных. К данным относятся и типы веществ, и типы конструкций, и допустимость веществ в определенных конструкциях. А код, в соответствии с этими данными, должен назначать той или иной конструкции то или иное вещество. В соответствии с правилами, которые хранятся в базе данных.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[6]: Проектирование модели данных
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 25.07.07 09:20
Оценка:
Здравствуйте, Mazay, Вы писали:

M>Посмотрев на этот код, понял о какой таблице говорил Кирил. Я думал о типичной разводке связи многие-ко-многим, а имелась ввиду таблица соответствия идентификатора элемента к списку допустимых для него материалов.

Вы совершенно правы — я писал об обычной реляционной таблице, состоящей из двух колонок:

1) Тип материала.
2) Тип изделия.

В C++-коде такую таблицу можно представить в виде std::map<,>.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[6]: Проектирование модели данных
От: dorofeevilya Россия  
Дата: 25.07.07 09:25
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:


КЛ>А зачем данные, которые, к тому же, могут еще и поменяться хардкодить в код? По последним данным известно около 7 млн. органических и 160 тыс. неорганических соединений естественного и искусственного происхождения. Согласитесь, неразумно каждое из них представлять в виде класса.


Насчет 7160000 соединений мне кажется, что это не отдельные классы, а экземпляры одного из двух классов (class ОргВещество и class НеоргВещество), также как и, допустим, бетоны марки B20 и B25 — два экземпляра class Бетон : Материал, а не два отдельных класса.

КЛ>Поэтому конкретные данные должны содержаться в файле или в базе данных. К данным относятся и типы веществ, и типы конструкций, и допустимость веществ в определенных конструкциях. А код, в соответствии с этими данными, должен назначать той или иной конструкции то или иное вещество. В соответствии с правилами, которые хранятся в базе данных.


А зачем тогда кодировать модель данных вообще, если все содержится в некой базе данных? Или я неправильно Вас понял?
Re[6]: Проектирование модели данных
От: dorofeevilya Россия  
Дата: 25.07.07 09:30
Оценка:
Здравствуйте, Mazay, Вы писали:

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


D>>Здравствуйте, Кирилл Лебедев, Вы писали:


КЛ>>>Здравствуйте, dorofeevilya, Вы писали:


D>>>>Над общей архитектурой уже давно плотно думаю На этой проблеме застопорился.

КЛ>>>Почему материал нельзя представить в виде идентификатора, а зависимость между изделием и материалом — в виде таблицы?

D>>А в чем разница? Так или иначе будет возможность назначить неподходящий материал элементу. Как я понимаю, здесь необходимо делать проверку типа материала при назначении его элементу. Вопрос, когда выполнять эту проверку: на этапе компиляции или во время выполнения. Во время выполнения можно сделать так:


M>// страшный свич ы ужасе поскипан


D>>А реально ли предоставить эту проверку компилятору?

M> Реально — через [маркерные] интерфейсы, но незачем. Лучше если это можно будет настраивать без изменения кода.

M>Посмотрев на этот код, понял о какой таблице говорил Кирил. Я думал о типичной разводке связи многие-ко-многим, а имелась ввиду таблица соответствия идентификатора элемента к списку допустимых для него материалов.

M>В коде у тебя должно быть что-то вроде такого мэпа:


M>
M>map<ElementType, set<MaterialID> > allowedMaterials;
M>



M>Тогда код будет такой:


M>

M>void Element::setMaterial(Matetrial *material)
M>{
M>   if (allowedMaterials[this->getType()].contains(material->getId()))
M>   {
       this->>setMaterial(material);
M>   } else // error!
M>}
M>



1) Почему не стоит использовать "маркерные" интерфейсы? Чем хуже? Я думал, что предоставить проверку компилятору лучше, чем делать то же самое в рантайме. Объясните, в чем я неправ.

2) И все же. Как использовать такие интерфейсы. Если можно, примерчик какой-нить...
Re[7]: Проектирование модели данных
От: Mazay Россия  
Дата: 25.07.07 10:34
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>1) Почему не стоит использовать "маркерные" интерфейсы? Чем хуже? Я думал, что предоставить проверку компилятору лучше, чем делать то же самое в рантайме. Объясните, в чем я неправ.

В том что полагаешь, что нашёл серебряную пулю. В некоторых случаях лучше отдавать проверку компилятору, а в некоторых оставлять на рантайм. Это зависит от предметной области. Вот ты выше предложил разбиения на class ОргВещество и class НеоргВещество или на class Бетон и class ЕщёЧтоТоТогоЖеУровняАбстракции. А мы с высоты собственного опыта советуем тебе вообще не разбивать, а оставить только class Вещество.


D>2) И все же. Как использовать такие интерфейсы. Если можно, примерчик какой-нить...


Да какой-тут примерчик:
class Generic_A
{
       void foo() {/* код */}
       void bar() {/* код */}
       void car() {/* код */}
};

class SuitableForB //чисто абстрактный класс
{
       virtual void foo() = 0;
       virtual void bar() = 0;
       //всё. больше ничего.
}


class SuitableForС //чисто абстрактный класс
{
       //вообще может быть пустым.
}

class Derived_A1 : public Generic_A, SuitableForB { ... };
class Derived_A2 : public Generic_A, SuitableForB, SuitableForC { ... };
class Derived_A3 : public Generic_A, SuitableForB, SuitableForC { ... };
class Derived_A4 : public Generic_A { ... };

class B
{
    SuitableForB * a;
    void use() { a->foo(); a->bar(); a->сar();}
};

class C
{
    SuitableForC * a;
    void use() { a->сar(); }
};
Главное гармония ...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.