Динамическая классификация объектов
От: borisman2 Киргизия  
Дата: 01.10.04 09:24
Оценка: 71 (6)
+ Письмо в RSDN


— <<Приветсвие>>
Здравствуйте товарищи программисты!

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

Строго говоря, этот пост не является каким-то конкретным вопросом. Просто я излагаю свою небольшую идею и хочу знать, как эту идею примет уважаемое сообщество RSDN. Единственная просьба — не бейте камнями, а точнее вопросами — "Да зачем все это надо ??? У меня вот нет таких проблем... потому что я пишу вот так мол и так...", поймите, я не могу отмахнуться от задачи, просто отказавшись ее решать.
— <<Введение>>
Меня зовут Борис, я работаю в Программе Микрофинансирования Европейского Банка Реконструкции и Развития. Одна из задач, которые передо мной стоят — задача отслеживания заявок, кредитов, заемщиков и т.д. в банках-партнерах, с которыми работает наша Программа. Не вдаваясь а дальнейшие детали, перейду непосредственно к вопросу.

+ <<Задача: модель данных>>
В настоящий момент я разрабатываю модель данных для довольно сложной комплексной проблемы учета. Модель включает в себя массу информации из реального мира, которую не так то просто промоделировать. Конечным результатом должен стать модуль, написанный на языке Python, т.е. грубо говоря, некая иерархия классов, отражающая предметную область.

Я буду приводить примеры на С++ чтобы было более понятно аудитории, потому как по данным опроса большинство программистов RSDN используют C++. Пожалуйста, отнеситесь со снисхождением к коду, который я буду писать на С++, потому что у меня нет возможности (да и желания) его хотя-бы раз скомпилировать, а потому возможны разные синтаксические ошибки.
+ <<Основной затык>>
Разрабатывая проблему, я столкнулся со следующим весьма печальным (и, в общем-то, известным) затыком: статическая объектная модель данных (т.е. иерархия классов) не может достаточно полно и точно описать предметную область.

Сразу оговорюсь, что при разработке модели Я НЕ ПЫТАЛСЯ объять необъятное, т.е. разработать модель для всех возможных случаев. Это попросту невозможно.
— <<Пример>>
В предметной области имеются люди как таковые, то есть некоторые объекты, имеющие фамилию имя и отчество (строго говоря, для какой-то другой предметной области важнее будет, что люди имеют, скажем, рост и вес, но в данном случае я разрабатываю совершенно конкретную областьи потому важно именно ФИО), на C++ это может быть описано примерно так:


class Person {
    public string first_name;
    public string last_name;
    public string third_name;
}


Люди могут при этом быть пользователями системы:

class User: public Person {
    public string login;
    public string password;
}

Но кроме этого, люди могут быть еще и подателями заявлений

class Applicant: public Person {
    public Application application;
    public date applicationDate;
}


Может быть такая ситуация, что человек является подателем заявления (Applicant) но не является пользователем системы (User). А может быть и наоборот — человек может являться пользователем системы и не являться подателем заявления.
— <<Почему так происходит>>
Проблема в том, что статическое описание классов (диаграмма классов) не может описать динамический характер предметной области.
— <<Обычное решение>>
Обычное решение (к сожалению) состоит в том, чтобы отказаться от классического ОО моделирования предметной области, исскуственно упрощая модель данных, например:

class User {
    public string first_name;
    public string second_name;
    public string third_name;
    public string login;
    public string password;
}

class Appplicant {
    public string first_name;
    public string second_name;
    public string third_name;
    public Application app;
}

Преимущества и недостатки такого подхода говорят сами за себя:
\- Это проще реализовать
\- К сожалению, теперь уже ПРИЛОЖЕНИЕ должно знать о связях между объектами, т.е. приложение должно знать, скажем, что пользователь и заявитель с одинаковыми ФИО — это одно и то же лицо.


— <<Возможное статическое решение>>
Ранее я уже сталкивался с подобной проблемой в более мелких масштабах и решал я ее так:

class Person {
    ...
}

class User {
    public Person person;
}

class Applicant {
    public Applicant applicant;
}


Далее все понятно. Но есть несколько затыков:
1) Можно определить, что пользователь является человеком, но не наоборот (нельзя определить что данный конкретный человек является пользователем)
2) Четкую иерархию классов мы подменили исскуственной иерархией агрегации. Это, в общем, терпимо, однако заставляет нас писать дополнительный проблемно-ориентированный код, который реализует иерархию. Это "грязный хак".


До сих пор я считал, что это вообще единственное разумное решение.
+ <<Шаблонный подход, приближающий нас к идеалу>>
— <<Множественное наследование>>
Выразить факт того, что человек является пользователем или заявителем можно, используя множественное наследование
class PersonMixin {
    public string first_name;
    public string second_name;
    public string third_name;
}

class UserMixin {
    public string login;
    public string password;
}

class Applicant {
    public Application application;
}

теперь конкретный объект можно создать так:
class ConcreteUser: public PersonMixin, public UserMixin {
}
ConcreteUser user = ConcreteUser()

Множественное наследование не такая уж страшная вещь, как ее малюют. До тех пор, конечно, пока Вы не заморачиваетесь с виртуальными классами, т.е. пока классы, от которых Вы наследуете, не слишком сложны.
— <<Шаблоны>>
Шаблоны позволяют упростить использование множественного наследования
template <typename T, typename B> class Dual: public <T>, public <B> {
}

user = Dual<PersonMixin, UserMixin>()


примерно так или что-то в этом духе.
— <<Затык>>
К сожалению, и этот подход ведет в тупик, потому что невозможно изменить класс объекта в рантайме, т.е. если, например, был у нас Петр Петрович Иванов, и стал он вдруг пользователем системы, это мы уже не сможем выразить в коде. Вот если ЗАРАНЕЕ известно, что Петр Петрович является пользователем системы — тогда все Ок.
— <<Динамическое решение>>
К большому моему счастью (и, конечно, к несчастью, потому что в мире вообще сплошные палки с двумя концами) я пишу задачу не на С++, а на Питоне.
Питон является динамическим языком с очень мощными возможностями интроспекции. В частности, он позволяет изменять класс переменной ВО ВРЕМЯ ИСПОЛНЕНИЯ ПРОГРАММЫ!

Идея, кажется, не новая, потому что смутно помню, что я это уже где-то встречал. Но простота, с какой ее можно реализовать на Питоне, меня поразила...

Поэтому. Можно писать код в таком виде.

obj = object() # какой-то абстрактный объект

promote(obj, User) # объект стал пользователем
obj.login="login" 
obj.password="password"

promote(obj, Person) # объект кроме того, что был пользователем, стал еще и человеком
obj.firstName = "Пасько"
obj.firstName = "Борис"
obj.firstName = "Сергеевич"

promote(obj, Person) # объект кроме того, что был пользователем и человеком, стал еще и заявителем
obj.application = Application(...)

Определения классов притимивны, как и в шаблонном примере:
class User:
    login = None
    password = None

class Person:
    firstName = None
    lastName = None
    thirdName = None
    
class Applicant:
    application = None

Реализация функции promote очень проста, но для ее понимания Вам понадобится разобраться в том, как организованы классы в Питоне. Можете этот пункт просто пропустить
def promote(obj, klass):
    bases = obj.__class__.__bases__
    bases = list(bases) # потому что obj.__class__.__bases__ - это не список, а tuple
    bases.append(klass) # !!!
    obj.__class__.__bases__=tuple(bases)





— <<Что это дает???>>
А дает такой подход несколько приятных возможностей.
1) Мы не ломаем ООП подход к нашей модели, просто рассматриваем возможность того, что классы могут изменяться в рантайме, т.е. расширяем ОО моделирование и на рантайм.
2) Мы можем использовать базовые возможности языка для работы с такими объектами. Например, при агрегационно подходе для того, чтобы изменить фамилию пользователя мы написали бы что-то вроде:
    
user.person.firstName = "Иванов"

в данном случае мы просто пишем
user.firstName = "Иванов"

Мы можем использовать явные проверки для определения класса объекта:

isinstance(obj, User)
isinstance(obj, Applicant)
...
Re: Динамическая классификация объектов
От: flax Беларусь  
Дата: 01.10.04 09:57
Оценка:
Разве не то же самое можно с помощью

1) Распознавание конвертируемости и наследования на этапе компиляции.
2) Оболочки вокруг TypeInfo для рантайма

("Modern C++ design" by Alexandresky)

Сорри, если закрыв глаза шашкой...
Re[2]: Динамическая классификация объектов
От: borisman2 Киргизия  
Дата: 01.10.04 10:59
Оценка:
Здравствуйте, flax, Вы писали:

F>1) Распознавание конвертируемости и наследования на этапе компиляции.

F>2) Оболочки вокруг TypeInfo для рантайма

К сожалению я не знаком ни с первым пунктом, ни со вторым. Я почитаю и отвечу.

Однако, дело ведь тут не в распознавании типа и конвертируемости, а в том, чтобы в рантайме ИЗМЕНИТЬ класс объекта, скажем, добавить еще один класс, к которому данный объект принадлежит/от которого он наследован.

Говоря очень утрированно, сегодня я, скажем, User, который работает в Ворде, а завтра подучился — глядишь и не только User, а еще и Programmer, который пишет под ворд макросы. А послезавтра выясняется, что я еще и Taxpayer.... и т.д.
Re: Динамическая классификация объектов
От: Pretorean  
Дата: 01.10.04 11:00
Оценка:
Hello, borisman2!
You wrote on Fri, 01 Oct 2004 09:24:03 GMT:

Тоесть обьект обладает каким-то динамическим набором "возможностей" ?
Если да, то:

1. какждую "возможнось" сделать как СОМ-интерфейс обьекта ...
2. сделать класс, реализующий все эти интерфейсы ...
3. сделать, так чтобы ф-ция QueryInterface знала какой набор интерфейсов доступен в данный момент экемпляру обьекта, и возвращала только доступные ...
4. перед работой пробуем получить нужный интерфейс, если получилось работаем, если нет, то обьект это не может ..

Думаю что при таком подходе сохранятся все преемущества, описаные на примере реализации на Питоне

With best regards, Aleksey Radionov.
Posted via RSDN NNTP Server 1.8
Re[3]: Динамическая классификация объектов
От: flax Беларусь  
Дата: 01.10.04 11:47
Оценка:
Здравствуйте, borisman2, Вы писали:

BB>чтобы в рантайме ИЗМЕНИТЬ класс объекта


Тогда прямиком в рубрику dotnet. Там любят reflection по метаданным
Re: Динамическая классификация объектов
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 01.10.04 12:19
Оценка: 4 (1) +1
Здравствуйте, borisman2, Вы писали:

B>Люди могут при этом быть пользователями системы:

B>Но кроме этого, люди могут быть еще и подателями заявлений

Если нужно все сделать статически, то надо делать так:
TYPE
  Subject = OBJECT
    Person    : Person;    (* Если Person    = NIL, значит он не персона, system trap *)
    User      : User;      (* Если User      = NIL, значит он не юзер *)
    Applicant : Applicant; (* Если Applicant = NIL, значит он не аппликант *)
  END;

  Subjectable = ABSTRACT OBJECT
    Subject   : Subject;
  END;

  Person = OBJECT (Subjectable)
    FirstName : STRING; 
    LastName  : STRING;
    ThirdName : STRING;
  END;

  User = OBJECT (Subjectable)
    Login     : STRING; 
    Password  : STRING;
  END;

  Applicant = OBJECT (Subjectable)
    App       : Application; 
    AppData   : ApplicationData;
  END;


VAR X: Subject;
(* Должны выполняться тождества: *)
Если X.Person    # NIL, то X = X.Person.Subject
Если X.User      # NIL, то X = X.User.Subject      
Если X.Applicant # NIL, то X = X.Applicant.Subject
Re: Динамическая классификация объектов
От: StanislavK Великобритания  
Дата: 01.10.04 13:12
Оценка: 4 (1) +1
B> — <<Почему так происходит>>
B>Проблема в том, что статическое описание классов (диаграмма классов) не может описать динамический характер предметной области.

Почему бы не вынести такие свойства объекта в отдельные классы. А сам объект будет содержать набор этого хлама.
Например:


class BaseProp {
};

class LoginProp: public BaseProp {
  string login;
  string pwd;
};

class UserProp: public BaseProp {
  string name;
  int age;
};

class Object {
  std::vector<BaseProp*> props;
};


Выглядит сыро, особенно для С++ Идею можно немного додумать и научиться получать нужные атрибуты и читать их. Например, по некому идентификатору или как-нить еще, это по личным предпочтениям. Структура будет динамичной, добавление новых свойств не составит труда.
Re: Динамическая классификация объектов
От: eugals Россия  
Дата: 01.10.04 13:24
Оценка: 12 (1) +1
Здравствуйте, borisman2, Вы писали:

B>+ Письмо в RSDN

1. Нисколько не умаляя достоиств питона (я и сам на нем постоянно пишу), хочу всё-таки заметить, что здесь существует вполне приемлемое статическое решение:
    public interface IPerson
    {
        string FirstName { get; }
        string LastName  { get; }
    }

    public interface IUser: IPerson
    {
        string Login    { get; }
        string Password { get; }
    }

  ...
    
  // Соответственно, использовать это можно реализовав у твоих объектов функцию явного запроса интерфейса:
  IUser asUser = person.QueryInterface( IUser);
  ...


2. Что же касается питона, то и там в большистве приведенных примеров также можно было обойтись без явной смены класса объекта.
Это же динамический язык. Для радостей навроде такого:
B>в данном случае мы просто пишем
B>
B>user.firstName = "Иванов"
B>

Достаточно просто грамотно перекрыть метод __getattr__.

Единсвенно, что эта проверка не будет проходить:
B>
B>isinstance(obj, User)
B>isinstance(obj, Applicant)
B>...
B>

Но оно и не нужно, если вдуматься. Вот такое решение выглядит ничуть не сложнее:
obj.is_a( User)
obj.is_a( Applicant)
...


3. Ну, и последнее. Функция promote:
def promote(obj, klass):
    bases = obj.__class__.__bases__
    bases = list(bases) # потому что obj.__class__.__bases__ - это не список, а tuple
    bases.append(klass) # !!!
    obj.__class__.__bases__=tuple(bases)

Ты в курсе, что этот код изменяет базовый тип не только конкретного объекта, а и всех его братьев и сестер?
Если уж писать, то как-то так:
def promote(obj, klass):
    class NewClass( obj.__class__, klass):
            pass
        obj.__class__ = NewClass
... << RSDN@Home 1.1.4 beta 2 >>
Re: Динамическая классификация объектов
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.10.04 13:26
Оценка: 18 (3) +1
Здравствуйте, borisman2, Вы писали:

B>+ Письмо в RSDN

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

По поводу множественной функциональности вроде как сейчас применяют интерфейсы. (Как тут уже было замечено). При моделировании все вроде бы должно сходиться идеально: мы описываем взаимоотношения объектов исключительно в терминах абстрактных интерфейсов, что потенциально позволяет нам состряпать класс, реализующий произвольную функциональность.

Есть две проблемы.
Перавя проблема — в комбинаторном взрыве количества классов. Пока мы рассуждаем в терминах IUser, IPerson — все очень здорово. У каждого IDocument есть IUser IDocument::Creator и IPerson Author. Все красиво, здорово, можно строить различные алгоритмы, требующие минимум от остальных компонентов системы.
Но когда мы начинаем собственно строить эти "остальные компоненты" у нас появляются и User, и Person, и PersonUser, который может быть сразу и автором и создателем. При этом вроде никакого особенного функционала в нашем PersonUser-то и нету. Так, банальная суперпозиция User и Person. Дальше станет еще хуже, когда список возможных ролей начнет расти.

Вторая проблема — в том, что один и тот же объект может играть в разное время разные роли. Раньше я думал, что это можно обойти при помощи замены объекта. То есть у нас есть либо PersonUser& Person::BecomeUser(), либо наоборот PersonUser::PersonUser(User me). Таким образом мы берем и создаем более сложный объект по более простому. Предыдущий объект умирает, и заменяется новым.
Vasya= Vasya.LearnToFly();

Увы, эта щтука совершенно не будет работать. Дело в том, что где-то далеко у нас может храниться ссылка на конкретно этот объект. Когда-то он был чем-то одним. Теперь, спустя много времни, мы сдуваем с этой ссылки пыль и проверям, а не реализует ли ссылаемый объект новый интерфейс? Увы, у нового объекта новая Identity. Либо ссылка прокисла, либо она показывает на васино привидение, либо мы мучительно обновляем все ссылки. Ни один из способов мне не нравится.

Мы должны сделать так, чтобы именно тот же самый объект сменил свой класс.

Во многих случаях обе проблемы скорее всего разрешимы именно агрегацией. У меня, как я уже жаловался, не хватает предметной области для упражнений в моделировании. Но то, что само приходит в голову, как правило решается легко и непринужденно. IUser превращается в IAccount, а персона получает возможность владеть несколькими аккаунтами. Адрес больше не является частью интерфейса IPerson (хотя так хочется его туда положить), а становится его агрегатом. Взамен персона получает адрес регистрации вместе с адресом постоянного проживания. При этом любой из них может оказаться адресом доставки для класса PersonalStoreRecord, реализующего IShoppingCartCustomer.
В таком случае вся динамика уходит в компоненты. А типизация остается статичной.

И вот я до сих пор не знаю — бывают ли ситуации, когда такой подход не сработает? По идее, это должна быть ситуация, в которой именно один и тот же объект можно равноправно трактовать как что-то одно, так и что-то другое. И более того, этот объект сначала этим чем-то другим не является, а потом — становится.

О! Вот задачка: был я простым персоном, а потом женился. Т.е. начал реализовывать
IMarried
{
   public IPerson Spouse 
     { get;}
}

Как бы обработать эту ситуацию?.. Будем думать.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Динамическая классификация объектов
От: borisman2 Киргизия  
Дата: 01.10.04 13:45
Оценка:
Здравствуйте, flax, Вы писали:

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


BB>>чтобы в рантайме ИЗМЕНИТЬ класс объекта


F>Тогда прямиком в рубрику dotnet. Там любят reflection по метаданным


О! В принципе вариант... Не знал я, что дотнет такое может...
Re[2]: Динамическая классификация объектов
От: eugals Россия  
Дата: 01.10.04 14:13
Оценка: 33 (2)
Здравствуйте, Sinclair, Вы писали:

S>О! Вот задачка: был я простым персоном, а потом женился. Т.е. начал реализовывать

S>
S>IMarried
S>{
S>   public IPerson Spouse 
S>     { get;}
S>}
S>

S>Как бы обработать эту ситуацию?..

Я бы сделал как-то так:
    public interface IEntity
    {
        IPerson QueryInterface( Type itf_type);
    }

    public interface IPerson: IEntity
    {
        string FirstName { get; }
        string LastName  { get; }
    }

    public interface IAdult: IPerson
    {
        void Marry( IPerson other);
    }

    public interface IMarried: IPerson
    {
        IPerson Spouse { get; }
    }

    class GenericPerson: IPerson
    {
        public string FirstName { get { return "John"; } }
        public string LastName  { get { return "Doe";  } }

        internal Collection<IPerson> roles;

        public IPerson QueryInterface( Type itf)
        {
            foreach( IPerson role in this.roles)
            {
                if( role is itf)
                    return role;
                IPerson res = role.QueryInterface( itf);
                if( is res is itf || res <> null)
                    return res;
            }
            return null;
        }
    }

    public class BasePersonRole: IPerson
    {
        protected IPerson _owner;

        public string FirstName { get { return _owner.FirstName; } }
        public string LastName  { get { return _owner.LastName;  } }

        public BasePersonRole( IPerson person)
        {
            _owner = person;
        }
        public IPerson QueryInterface( Type itf)
        {
            return null;
        }
    }

    public class MarriedRole: BasePersonRole, IMarried
    {
        IPerson _spouse;
        public MarriedRole( IPerson person, IPerson spouse): base(person)
        {
            _spouse = spouse;
        }

        public IPerson Spouse { get { return _spouse; } }
    }

    public class AdultRole: BasePersonRole, IAdult
    {
        public AdultRole( IPerson person): base(person)
        { }

        public void Marry( IPerson other)
        {
            // тут, понятно, нужна проверка на уникальность
            _owner.roles.Add( new MarriedRole( Owner, other));
        }
    }
... << RSDN@Home 1.1.4 beta 2 >>
Re: Динамическая классификация объектов
От: cvoronin Россия  
Дата: 01.10.04 17:04
Оценка:
Я бы применил что-нибудь подобное тому, как описано тут:
http://bdn.borland.com/article/0,1410,29678,00.html
Re[3]: Динамическая классификация объектов
От: akasoft Россия  
Дата: 01.10.04 18:06
Оценка: +3
Здравствуйте, borisman2, Вы писали:

Смотрю я на это, и вижу сплошные интерфейсы. Т.е. класс, выдающий (реализующий) несколько интерфейсов по запросу. Надо юзера — запросил интерфейс юзера, ещё кого — тоже просим. Проверить, поддерживает ли нужный нам интерфейс — тоже можем.

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

B>Говоря очень утрированно, сегодня я, скажем, User, который работает в Ворде, а завтра подучился — глядишь и не только User, а еще и Programmer, который пишет под ворд макросы. А послезавтра выясняется, что я еще и Taxpayer.... и т.д.


Ну а с другой стороны, это всё тот же объект юзер в одном числе, только сначала он был в коллекции Вордораб, потом добавили ссылку ещё и в Программёр, а послезавтра включили ещё в одну коллекцию. Те же Элементы и Коллекции, Пользователи и Группы... Разве нет?
... << RSDN@Home 1.1.4 beta 3 rev. 189 Тишь да гладь, да Божья благодать >>
Re[4]: Динамическая классификация объектов
От: borisman2 Киргизия  
Дата: 03.10.04 12:24
Оценка: +1
Здравствуйте, akasoft, Вы писали:

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


A>Смотрю я на это, и вижу сплошные интерфейсы. Т.е. класс, выдающий (реализующий) несколько интерфейсов по запросу. Надо юзера — запросил интерфейс юзера, ещё кого — тоже просим. Проверить, поддерживает ли нужный нам интерфейс — тоже можем.


Вкратце. Интерфейсы тут вообще не при чем.

Подробно:
Строго говоря, я даже слово "интерфейс" не разу не упоминал. Это потому, что я говорил не об интерфесах, а о попытке ЛУЧШЕ смоделировать реальный мир с его динамически меняющейся иерархией классов. Классическое объектно-ориентированное моделирование работает (очень грубо) по следующему алгоритму:
1) Определить все наличествующие в предметной области ОБЪЕКТЫ
2) Сгруппировать объекты с одинаковыми свойствами в КЛАССЫ
3) Построить из классов ИЕРАРХИЮ КЛАССОВ.
Здесь нет ни слова об интерфесах, а особенно, о запросах каких-то интерфесов. Я даже о методах-то не говорил. Вопрос интерфесов встает чуть позже, когда Вам нужно рассмотреть модель под каким-то усеченным углом, т.е. когда Вы хотели бы избавиться от ненужных деталей и оставить нужные — тогда вы начинаете работать над ВИДАМИ модели, которые, в частности, удобно представлять наборами и иерархиями интерфесов.

Я, в общем-то, не собраюсь рушить очень мне симпатичный метод объектного моделирования. Просто я говорю о том, что невозможно СТАТИЧЕСКИ смоделировать предметную обасть, т.е. отразить ее в СТАТИЧЕСКУЮ иерархию классов.

Цель разработанного мной способа не состоит в том, чтобы предоставить пользователю тот интерфейс, который ему нужен. Такая цель вовсе не ставилась. Задача была в том, чтобы пользователь мог определить, к какому КЛАССУ относится данный объект, и, при необходимости, классифицировать его по-новому, т.е. отнести его к новому классу предметов.

A>Нет, я конечно понимаю , что превращать один класс в другой или там даже не превращать, а расширять до другого, ведь это я так понял позволяет сделать Питон, интересно.


Да, интересно. Вопрос в том, имеет ли это практический смысл
Мне кажется, имеет. Однако могут быть и иные мнения.

A>Ну а с другой стороны, это всё тот же объект юзер в одном числе, только сначала он был в коллекции Вордораб, потом добавили ссылку ещё и в Программёр, а послезавтра включили ещё в одну коллекцию. Те же Элементы и Коллекции, Пользователи и Группы... Разве нет?


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

Насчет коллекций, мне кажется, или Вы немного недопоняли меня, или я — Вас. Если под коллекциями Вы имели в виду экстенты (extent), то есть списки всех объектов данного класса (как в ООБД), то, в общем-то, Вы частично правы. Однако это вовсе не те коллекции (типа TCollection в Delphi или Collection в Java), в которых обычно программисты складируют объекты. Такие коллекции опять же совершенно ни при чем.
Re[2]: Динамическая классификация объектов
От: borisman2 Киргизия  
Дата: 03.10.04 12:29
Оценка:
Здравствуйте, Pretorean, Вы писали:

P>Hello, borisman2!

P>You wrote on Fri, 01 Oct 2004 09:24:03 GMT:

P>Тоесть обьект обладает каким-то динамическим набором "возможностей" ?

P>Если да, то:

P>1. какждую "возможнось" сделать как СОМ-интерфейс обьекта ...

P>2. сделать класс, реализующий все эти интерфейсы ...
P>3. сделать, так чтобы ф-ция QueryInterface знала какой набор интерфейсов доступен в данный момент экемпляру обьекта, и возвращала только доступные ...
P>4. перед работой пробуем получить нужный интерфейс, если получилось работаем, если нет, то обьект это не может ..

P>Думаю что при таком подходе сохранятся все преемущества, описаные на примере реализации на Питоне


Да, кажется мы с Вами понимем друг друга. Осталось только добавить к Вашим рассуждениям метод, при помощи которого КЛИЕНТ сможет указать объекту, какого класса объектом он является (т.е. в Вашей терминилогии, какой он имеет интерфейс, хотя есть тонкая разница).

Да, можно попытаться сделать это на COM'е. Очень даже было бы интересно.
Re[2]: Динамическая классификация объектов
От: borisman2 Киргизия  
Дата: 03.10.04 12:37
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Здравствуйте, borisman2, Вы писали:


B>>Люди могут при этом быть пользователями системы:

B>>Но кроме этого, люди могут быть еще и подателями заявлений

СГ>Если нужно все сделать статически, то надо делать так:

СГ>[pascal]
СГ>TYPE
СГ> Subject = OBJECT
СГ> Person : Person; (* Если Person = NIL, значит он не персона, system trap *)
СГ> User : User; (* Если User = NIL, значит он не юзер *)
СГ> Applicant : Applicant; (* Если Applicant = NIL, значит он не аппликант *)
СГ> END;

Все верно, Вы сейчас идете по пути, который я описал как <<Возможное статическое решение>>

Проблема такого подхода заключается в том, что Вам придется заранее четко определить, к каким классом ПОТЕНЦИАЛЬНО может относиться объект. Иногда это очень даже разумно, например, когда известно точно, что люди могут быть слесарями, сантехникаим или уборщицами. Но это заранее накладывает ограничения на расширение модели в рантайме. Вы просто не сумеете предугадать, к каким классам ЕЩЕ можно отнести человека. Только, пожалуйста, не надо рубить с плеча — мол "это не нужно". В некоторых полуразумных приложениях может и понадобиться. Примером могут являться всем известные экспертные системы.

Впрочем, опять же, как я писал в описании <<Возможное статическое решение>>, это очень неплохой подход, до сих пор я вообще считал его единственно возможным
Re[2]: Динамическая классификация объектов
От: borisman2 Киргизия  
Дата: 03.10.04 12:45
Оценка:
Здравствуйте, StanislavK, Вы писали:

B>> — <<Почему так происходит>>

B>>Проблема в том, что статическое описание классов (диаграмма классов) не может описать динамический характер предметной области.

SK>Почему бы не вынести такие свойства объекта в отдельные классы. А сам объект будет содержать набор этого хлама.

SK>Например:


SK>
SK>class BaseProp {
SK>};

SK>class LoginProp: public BaseProp {
SK>  string login;
SK>  string pwd;
SK>};

SK>class UserProp: public BaseProp {
SK>  string name;
SK>  int age;
SK>};

SK>class Object {
SK>  std::vector<BaseProp*> props;
SK>};
SK>


Да, да, да! Именно так оно и будет выглядеть на С++.

SK>Выглядит сыро, особенно для С++ Идею можно немного додумать и научиться получать нужные атрибуты и читать их. Например, по некому идентификатору или как-нить еще, это по личным предпочтениям. Структура будет динамичной, добавление новых свойств не составит труда.


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

Кстати, Вы заметили, что наш с Вами подход к ОО моделированию сильно пошел в разрез с реализацией ООП как такового ? Это наша с Вами проблема или проблема ООП ? Я давно подозреваю, что ООП вообще вещь очень мутная — черти там водятся...
Re[2]: Динамическая классификация объектов
От: borisman2 Киргизия  
Дата: 03.10.04 16:58
Оценка:
Прежде всего, огромное спасибо, господин товарищ eugals! Ваш ответ очень мне помог и я несомненно включу его как часть проектной документации, в которую я уже подшил свое письмо.

Вы писали:

E>1. Нисколько не умаляя достоиств питона (я и сам на нем постоянно пишу), хочу всё-таки заметить, что здесь существует вполне приемлемое статическое решение:


Проблема в том, как это приемлемо реализовать. Вот тут очень хорошо заострено внимание на этом вопросе:
http://www.rsdn.ru/Forum/Message.aspx?mid=833752&amp;only=1
Автор: Sinclair
Дата: 01.10.04

проблема состоит в том, как добавлять в существующие объекты новую функциональность.

E>2. Что же касается питона, то и там в большистве приведенных примеров также можно было обойтись без явной смены класса объекта.

E>Это же динамический язык. Для радостей навроде такого:
B>>в данном случае мы просто пишем
B>>
B>>user.firstName = "Иванов"
B>>

E>Достаточно просто грамотно перекрыть метод __getattr__.

Абсолютно верно! Однако, ведь весь огород городится вовсе не из-за того, чтобы получить доступ к каким-то там новым атрибутам. Весь огород городился ради того, чтобы можно было объект рассматривать как объект ДЕЙСТВИТЕЛЬНО нового класса. Хотя, возможны, повторю, альтернативные решения. Кстати говоря, в первой реализации у меня так примерно и было сделано — я переопределял __getattr__ и все пучком. Но потом я задумался — а не дурак ли я? Получается, что я пытаюсь исскуственно приделать к объекту свойства другого класса. Зачем ? Почему бы объекту не стать обхектом нового класса ? Концептуально это проще и понятнее, чем рассматривать хитрые "прокси", которые, допустим, вызывают непонятно какие объекты на другой стороне.

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

E>Единсвенно, что эта проверка не будет проходить:

B>>
B>>isinstance(obj, User)
B>>isinstance(obj, Applicant)
B>>...
B>>

E>Но оно и не нужно, если вдуматься. Вот такое решение выглядит ничуть не сложнее:
E>
E>obj.is_a( User)
E>obj.is_a( Applicant)
E>...
E>


Тоже верно! Но только зачем создавать дополнительные сущности без необходимости?

E>3. Ну, и последнее. Функция promote:

E>Если уж писать, то как-то так:
E>
E>def promote(obj, klass):
E>    class NewClass( obj.__class__, klass):
E>            pass
E>        obj.__class__ = NewClass
E>


Вот тут снимаю перед Вами шляпу, которую я прошляпил, когда писал эту функцию. Огромное спасибо. Это я действительно проглядел... Причем, заметьте, Ваше решение короче и понятней, чем мое. К тому же оно правильное, что немаловажно
Re[3]: Динамическая классификация объектов
От: borisman2 Киргизия  
Дата: 03.10.04 17:03
Оценка:
Здравствуйте, eugals, Вы писали:

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


S>>О! Вот задачка: был я простым персоном, а потом женился. Т.е. начал реализовывать

S>>Как бы обработать эту ситуацию?..

E>Я бы сделал как-то так:

[поскипано]

Собственно, Вы предложили (как я понял) тот же самый подход, что и здесь:
http://www.rsdn.ru/Forum/Message.aspx?mid=833706&amp;only=1
Автор: StanislavK
Дата: 01.10.04

только, справедливости ради, я хотел бы сказать, что у StanislavK это получилось более просто, понятно и абстрактно.

Впрочем, я может быть чего-то и недопонял.
Re[3]: Динамическая классификация объектов
От: WolfHound  
Дата: 03.10.04 19:26
Оценка:
Здравствуйте, borisman2, Вы писали:

B>Кстати, Вы заметили, что наш с Вами подход к ОО моделированию сильно пошел в разрез с реализацией ООП как такового ?

Какого ООП? Они бывают разные... Есть
1)Наследование
2)Инкапсуляция
3)Полиформизм
А есть ООП по Алану Кейю(на счет имени не уверен )
1)Объект — базовая единица системы.
2)Объекты обладают состоянием.
3)Единственным способом взаимодействия между объектами является посылка сообщения. Объекты сами определяют как обрабатывать сообщения.
B>Это наша с Вами проблема или проблема ООП ? Я давно подозреваю, что ООП вообще вещь очень мутная — черти там водятся...
Дык вот ваш подход очень даже вписывается в ООП по Кейю
... << RSDN@Home 1.1.4 rev. 185 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.