Pull to refresh

Comments 63

UFO just landed and posted this here
Начальные данные таковы, что это не была одна транзакция. Это были две модели разных операций в разных хранилищах.
UFO just landed and posted this here
обращение в транзакцию убьет информацию, которая была изначально в хранилищах, а мы этого не хотим. Ведь никто не захочет, чтобы кто-то извне менял его модель. Сидоров хочет, чтобы информация о продажах хранилась в том виде, в котором он ее создал. Кому-то, кому надо, пусть создает новые модели, но Сидоров хочет видеть то, что он сделал. Он не согласен на транзакцию, он утверждает, что это была продажа.
UFO just landed and posted this here
Транзакция — не есть продажа. Это изменилось. Если мы перепишем класс sale в виде обертки над transaction, то вопрос: что делать, если появится третья точка зрения, в которой эта же операция была операцией по истреблению остатков. Если мы перепишем класс истреблений остатков в виде обертки над классом транзакций, то получится, что класс транзакций — это и есть класс неклассифицированных объектов учета. То есть, это будет еще один способ моделирования объекта учета и его классификации при помощи оберток.
UFO just landed and posted this here
using System;
using System.Collections.Generic;
using static System.Console;
using static System.FormattableString;

namespace InterfacesSample
{
    interface IColoredEntity
    {
        int ColorCode { get; }
    }

    interface IVehicle : IColoredEntity
    {
        string VinNumber { get; }
        int WheelCount { get; }
        int MaxCarryingKgs { get; }
    }

    interface IBuilding : IColoredEntity
    {
        bool IsResidental { get; }
        int FloorCount { get; }
    }

    class PassengerCar : IVehicle
    {
        public string VinNumber { get; }
        public int WheelCount => 4;
        public int MaxCarryingKgs => 400;
        public int ColorCode { get; }
        public PassengerCar(string vinNumber, int colorCode)
        {
            VinNumber = vinNumber;
            ColorCode = colorCode;
        }
    }

    class ResidentalBuilding : IBuilding
    {
        public bool IsResidental => true;
        public int FloorCount { get; }
        public int ColorCode { get; }
        public ResidentalBuilding(int floorCount, int colorCode)
        {
            if (!(floorCount >= 1 && floorCount <= 100))
                throw new ArgumentOutOfRangeException(nameof(floorCount));

            FloorCount = floorCount;
            ColorCode = colorCode;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var car1 = new PassengerCar(vinNumber: "VIN 1", colorCode: 0);
            var car2 = new PassengerCar(vinNumber: "VIN 2", colorCode: 1);

            var house1 = new ResidentalBuilding(floorCount: 100, colorCode: 2);
            var house2 = new ResidentalBuilding(floorCount: 100, colorCode: 3);

            var coloredObjects = new List<IColoredEntity>
            {
                car1,
                car2,
                house1,
                house2
            };

            var vehicles = new List<IVehicle>
            {
                car1,
                car2
            };

            WriteLine("Colored Objects:");
            foreach (var coloredObject in coloredObjects)
            {
                WriteLine(Invariant(
                    $"Color: {coloredObject.ColorCode:X8}"));
            }

            WriteLine("Vehicles:");
            foreach (var vehicle in vehicles)
            {
                WriteLine(Invariant(
                    $"Vin Number: {vehicle.VinNumber}; Color: {vehicle.ColorCode:X8}"));
            }

            // Output:
            //Colored Objects:
            //Color: 00000000
            //Color: 00000001
            //Color: 00000002
            //Color: 00000003
            //Vehicles:
            //Vin Number: VIN 1; Color: 00000000
            //Vin Number: VIN 2; Color: 00000001
        }
    }
}
А можно попросить объяснить мне что такое предметная область? А то я не понимаю, какое отношение имеет цвет, когда описывается предметная область сбыта автомобилей.
Есть условие задачи. Оно сформулировано в статье. Надо ее решить. Это не практическая задача по моделированию сбыта авто. Это мысленный эксперимент.
Я понимаю что мысленный, но звучит он как «овощи очень вредны, ведь если съесть три тонны лука — то умрешь».
Мне кажется что если задачу поставить заведомо неправильным образом, то она может привести к неправильным решениям. Почему Вы говорите авто-плаволка, а не транспортное средство? Почему поведение зависит от второстепенных данных не относящихся к предметной области, как например цвет?
Если съесть три тонны лука, то умрешь. Это верно. Но из этого не следует вредность овощей. Из какого тезиса в моей задаче я сделал неверный вывод? То есть, если можно: тезис, вывод, и то, почему он неверный.
И почему не введено понятие «товар» с которым бы и проводились все операции. В условиях явно перемешались области-слои, какой Вывод Вы хотели получить? И Вы описываете структуру, а не поведение модели предметной области.
Я хочу решение поставленной задачи. Более ничего. Есть два хранилища, их надо соединить в одно. Как бы программист решал эту задачу? Вот мой интерес. При этом стоит условие — для пользователя ничего не должно поменяться — ни названия объектов, ни их свойства.

Программист бы спросил "Зачем?". То есть, какая цель у этой операции.

Будем считать, что ему ответили на этот вопрос, дали денег и заключили контракт. Как он будет это делать?

"Как" он будет это делать напрямую зависит от того, "что" ему ответили на этот вопрос. Он ведь не просто так спросил. А в такой формулировке ответ будет такой: будем считать, что он взял и сделал.

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

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


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


было:

операции_продажи: (хранилище 1)
id: 123, время: 2017-06-10 10:26, товары: [A,B,C]
id: 124, время: 2017-06-10 10:27, товары: [D,E,F]

операции_покупки: (хранилище 2)
id: 678, время: 2017-06-10 10:28, товары: [A,B,C]
id: 679, время: 2017-06-10 10:29, товары: [D,E,F]

стало:

операции_продажи: (общее хранилище)
id: 123, время: 2017-06-10 10:26, товары: [A,B,C]
id: 124, время: 2017-06-10 10:27, товары: [D,E,F]

операции_покупки: (общее хранилище)
id: 123, время: 2017-06-10 10:28, товары: [A,B,C]
id: 124, время: 2017-06-10 10:29, товары: [D,E,F]

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


В свою очередь прошу привести пример вашего решения на основе этих данных.

Верно, одним из атрибутов объекта учета является первичный ключ. Но можно добавить еще и другие. Поскольку объект (не множество) — есть 4-хмерный объем, то атрибутами его могут быть границы этого объекта, например, временные: с и по.
ну так ответа однозначного нет. Все дело в том, что машина может быть выражена множеством вариантов в зависимости от позиции наблюдателя — предметной области. Если бы я продавал авто, то мне бы было удобно чтобы тип «авто» инкапсулировал даже цвет. Если бы я продовал машины по запчастям, то авто бы выражалось в виде коллекции её частей. Если бы мне сказали перепроектировать архитектуру магазина авто в магазин запчастей без изменения кода, да ещё за пару часов и пару тыщь, то скорее всего я бы послал просто нафиг.
Я перечитал ещё раз про цвет и транспорт и хочу поправить себя — тут я согласен с Вам, атрибута цвет у транспорта нет.
using System.Collections.Generic;
using System.Globalization;
using static System.Console;

namespace InterfacesSample2
{
    interface ILandVehicle
    {
        int MaxCarryingKgs { get; }
        int MaxPassengers { get; }
    }

    interface ISwimmingVehicle
    {
        int MaxCarryingKgs { get; }
        int MaxPassengers { get; }
    }

    interface IAmphibian : ILandVehicle, ISwimmingVehicle
    {
    }

    class Sedan : ILandVehicle
    {
        public int MaxCarryingKgs => 400;
        public int MaxPassengers => 4;
    }

    class Pickup : ILandVehicle
    {
        public int MaxCarryingKgs => 500;
        public int MaxPassengers => 1;
    }

    class Boat : ISwimmingVehicle
    {
        public int MaxCarryingKgs => 450;
        public int MaxPassengers => 3;
    }

    class UniversalVehicle : IAmphibian
    {
        public int MaxCarryingKgs => 250;
        public int MaxPassengers => 2;
    }

    class SwimmingCar : IAmphibian
    {
        public int MaxCarryingKgs => 300;
        public int MaxPassengers => 3;

        int ISwimmingVehicle.MaxCarryingKgs => 200;
        int ISwimmingVehicle.MaxPassengers => 1;
    }

    class Amphibian : IAmphibian
    {
        int ILandVehicle.MaxCarryingKgs => 350;
        int ILandVehicle.MaxPassengers => 3;

        int ISwimmingVehicle.MaxCarryingKgs => 250;
        int ISwimmingVehicle.MaxPassengers => 1;
    }

    class Program
    {
        static void Main(string[] args)
        {
            var sedan = new Sedan();
            var pickup = new Pickup();
            var universalVehicle = new UniversalVehicle();
            var swimmingCar = new SwimmingCar();
            var amphibian = new Amphibian();
            var boat = new Boat();

            var landVehicles = new List<ILandVehicle>()
            {
                sedan, pickup, universalVehicle, swimmingCar, amphibian
            };

            var swimmingVehicles = new List<ISwimmingVehicle>
            {
                universalVehicle, swimmingCar, amphibian, boat
            };

            var amphibians = new List<IAmphibian>
            {
                universalVehicle, swimmingCar, amphibian
            };

            WriteLine("Land Vehicles:");
            foreach (var vehicle in landVehicles)
            {
                WriteLine(string.Format(
                    CultureInfo.InvariantCulture,
                    "MaxCarryingKgs: {0}; MaxPassengers: {1}",
                    vehicle.MaxCarryingKgs, vehicle.MaxPassengers));
            }

            WriteLine("Swimming Vehicles:");
            foreach (var vehicle in swimmingVehicles)
            {
                WriteLine(string.Format(
                    CultureInfo.InvariantCulture,
                    "MaxCarryingKgs: {0}; MaxPassengers: {1}",
                    vehicle.MaxCarryingKgs, vehicle.MaxPassengers));
            }

            WriteLine("Amphibians:");
            foreach (var vehicle in amphibians)
            {
                WriteLine(string.Format(
                    CultureInfo.InvariantCulture,
                    "MaxCarryingKgs: {0}/{1}; MaxPassengers: {2}/{3}",
                    ((ILandVehicle)vehicle).MaxCarryingKgs,
                    ((ISwimmingVehicle)vehicle).MaxCarryingKgs,
                    ((ILandVehicle)vehicle).MaxPassengers,
                    ((ISwimmingVehicle)vehicle).MaxPassengers));
            }

            // Output:
            //Land Vehicles:
            //MaxCarryingKgs: 400; MaxPassengers: 4
            //MaxCarryingKgs: 500; MaxPassengers: 1
            //MaxCarryingKgs: 250; MaxPassengers: 2
            //MaxCarryingKgs: 300; MaxPassengers: 3
            //MaxCarryingKgs: 350; MaxPassengers: 3
            //Swimming Vehicles:
            //MaxCarryingKgs: 250; MaxPassengers: 2
            //MaxCarryingKgs: 200; MaxPassengers: 1
            //MaxCarryingKgs: 250; MaxPassengers: 1
            //MaxCarryingKgs: 450; MaxPassengers: 3
            //Amphibians:
            //MaxCarryingKgs: 250/250; MaxPassengers: 2/2
            //MaxCarryingKgs: 300/200; MaxPassengers: 3/1
            //MaxCarryingKgs: 350/250; MaxPassengers: 3/1
        }
    }
}
как теперь вы назовете моделируемый объект? Автомобиль-плавсредство? А, если потом появятся другие классы, к которым относится этот объект? Будете перечислять их названия через дефис, и говорить: автомобиль-плавсредство-альфа-омега?

Зачем что-то выдумывать, чтобы назвать моделируемый объект? Если мы моделируем классы для хранения моделей плавательных средств и классы для хранения моделей автомобилей, то у них уже есть названия – это названия моделей. Например, для глиссирующего автомобиля-амфибии «Тритон» мы выберем имя класса Тритон.
Можно выбирать названия под каждый новый класс. Можно действовать и так, но тогда количество слов невероятно возрастет — в соответствии с декартовым произведением множеств. Тогда язык лишится своей силы — универсальности.
Мы же выполняем классификацию существующих объектов предметной области, а не всех возможных и невозможных объектов, которые появятся (или не появятся) в будущем. А это лишь небольшое подмножество из произведения множеств значений их свойств. И классифицируя это подмножество, ничего придумывать не нужно, так как обычно люди всему дают названия. Возьмите для примера любую модель транспортного средства.
Оечь идет о возможности объединения разных хранилищ без переделки структуры хранилищ. Это требование к расширяемости модели. Я показываю, что при помощи ООП это сделать невозможно, потому что мы натыкаемся на необходимость менять структуру. Однако существуют подходы к моделированию, при которых модель расширяема без изменения структуры данных. Речь о том, как должна выглядеть такая модель, и что она значит?

Я вам выше показал, что никакую структуру менять не надо. Каждая таблица БД маппится на соответствующий ей тип в ООП. Если нам нужен учет самых абстрактных объектов, то это будет еще одна таблица и соответствующий ей тип.

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

У вас тоже надо что-то менять в структуре. Стали рассматривать новый атрибут — вы ведь его вручную добавляете через интерфейс. То есть меняете модель.


Я не понимаю

Я вам там пример показал, как было и как стало. Отличие только в данных, но не в структуре.
Если вы не понимаете ООП, может не стоит рассуждать на эту тему?

Добавление нового атрибута, типа, правила, метода — это все делается единым образом через интерфейс но без изменения структуры хранилища и без изменения кода. В ООП надо менять структуру классов, или менять код. Но беда ООП не в этом, а в некорректных постулатах, возникших на ранних стадиях реализации языков. У истоков было все иначе, например, атрибуты были отделены от классов, но лишь потом они стали принадлежать им. Кто это сделал, тому просто не хотелось сильно думать.
без изменения структуры хранилища

Новый атрибут у типа это разве не изменение структуры?


это все делается единым образом через интерфейс

А в коде программ это делается единым образом через код. Код — это и есть модель. Если предметная область изменилась, надо изменять и модель.


и без изменения кода

В любой СУБД структура таблиц меняется без изменения кода СУБД.


У истоков было все иначе, например, атрибуты были отделены от классов

Это у каких например истоков?


Кто это сделал, тому просто не хотелось сильно думать.

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

Мы ходим по кругу. Я объясняю свое мнение насчет ООП. Я считаю, что оно вредно более, чем полезно. И это мнение, которое сложилось на основе общения с программистами, которые ничего, кроме ООП не знают. Те же, кто вырос из ООП, скорее согласятся со мной. Но это не более, чем моя точка зрения. Можно ее критиковать, но я предпочел бы общаться фактами. Если ООП создает атрибуты внутри типа, то это -факт. И это вредно с моей точки зрения. Так же я считаю, что создание метода внутри типа — не менее вредное заблуждение. И опять — это мое мнение. Вам нравится ООП, на здоровье! Каждому свое.

Многие из тех якобы фактов, которые вы говорите, попросту неверны. Я в очередной раз напоминаю, что я говорю не о том, кому что нравится, а о логических несоответствиях в ваших высказываниях. И многие из них исходят из того, что вы не знаете это самое ООП и не умеете им пользоваться. А когда дело доходит до конкретных примеров, вы просто уходите от ответа. Например, мою просьбу выше показать ваше решение на основе тех данных вы проигнорировали.

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

Это "немного" только в вашем представлении. На практике это приведет только к лишним сложностям, а в результате будет то же самое только в профиль — типы и атрибуты.


В статье вы рассказываете например такой факт: "Поэтому при слиянии двух моделей в OWL нам не придется делать столько работы, сколько пришлось бы делать в ООП.". Это неверно, и я привел пример это доказывающий. Вы никаких практических примеров вообще не привели.

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

Вот пример структуры хранилища (для MySQL), которая (в теории) позволяет сохранять данные об объектах (obj), различных способах их классификации (классах, моделях — classifier) и способах разбиения (конструкции — struct) целого (obj) на части (elem).


Вполне возможно, что на практике он работает не очень или даже очень не, но в теории, в качестве примера расширяемости моделей данных без изменения структуры хранилища вполне подходит, IMHO.

:( Ссылку не на тот скрипт дал. Вот правильный. Неверная ссылка ведет на более конкретную версию структуры данных под пример из статьи, а правильная — как раз на более универсальную версию.

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

именно его всегда упускают при разработке и заменяют самим подмножеством; и в случае если ваше подмножество вдруг стало не единственным, у вас не средств объединить эти подмножества, и вы создадите еще один класс «модель 2», то есть по сути дубликат класса «модель 1»

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

на самом деле, это действительно большая проблема, которая и порождает сложные современные фреймворки и миллионы разработчиков, вынудженных в них разбираться, вместо того, чтобы все делать просто
а завтра производители сменят «тритон» на «кватротрон», как это случилось, например, с Scion и Toyota, или добавят «пентатрон»

название модели не может быть классом, за исключением ситуации, когда название модели объединяет абсолютно все объекты этого класса, и вы уверены, что это имя никогда не изменится, но тогда это имя вообще не имеет никакого значения, и можно использовать просто «item»
Задача же не в создании классов на все времена. Это попросту невозможно. Если произойдут изменения в предметной области, можно будет внести изменения в классы и выпустить обновление. По-любому придется пересматривать классификацию, когда появятся летающие автомобили.
Классы и объекты классов — все это объекты учета, которые должны храниться единым образом, что и реализовано в OWL. Именно поэтому не надо ничего менять, поскольку структура моделируется так же, как и данные в ней. В этом сила OWL. И слабость ООП, о которой я пишу.
так вам все приложение придется переписывать и тестировать с каждым изменением, затрагивающим классификацию, уже не говоря о том, что этот код вы никогда не сможете использовать в других проектах, то есть затраты на разработку аналогичных продуктов у вас никогда не снизятся

классификацию не придется пересматривать, если «летающие автомобили» — это всего лишь еще одна опция в категории «товары»

максимум что вам будет нужно сделать — это расширить возможности нового товара, но доступ к нему остается тем же
Код отделен от структуры хранилища. Потому что все записывается в виде триплетов RDF. Даже алгоритмы, представления интерфейсных форм и проч… — все записывается единым образом. Код умеет считывать эти данные и производит нужные построения, вычисления, записи, удаления и проч.
так вам все приложение придется переписывать

Не переписывать, а дополнять и немного изменять, если мы правильно спроектировали иерархию классов и предусмотрели возможность развития и быстрого внесения изменений. Все приложения сейчас обновляются, и это в порядке вещей. «Soft» в отличие от «Hard» мягкий, то есть изменчивый. Бухгалтерский софт обновляется с изменением законодательства, драйвера обновляются с выходом новых устройств, и т.д. Изменения в моделируемой предметной области влекут изменения в приложении, что в этом необычного? И если руки не кривые, можно будет использовать созданные классы в аналогичных проектах.

классификацию не придется пересматривать

Давайте на примере. В классе «Транспортные средства» есть поля «Объем топливного бака, л» и «Расход топлива на 100 км». И мы реализовали функцию расчета, сколько можно проехать на полном баке без дозаправки «Максимальное расстояние» = Объем бака / Расход * 100. Отлично, но появляются летающие автомобили, которым требуется топливо на взлет и посадку. Мы добавляем класс «Летающий автомобиль» и поля «Расход топлива на взлет, л» и «Расход топлива на посадку, л». Если мы предусмотрительно объявили функцию «Максимальное расстояние» как виртуальную, то переопределяем ее: Расход на взлет + Объем бака / Расход * 100 + Расход на посадку. Как это сделать без ООП, если у нас один класс «Товары»?
Поэтому классификация в коде вводится не для того, чтобы разбить товары на группы или выделить какие-то опции. Классы различаются еще и поведением, то есть методами.
если у вас один класс товары, то вы можете добавлять туда любые категории товаров с любыми атрибутами, в том числе и летающие машины с любыми характеристиками

а вот к классу транспортные средства вы уже не добавите товары для туризма, которые может быть выгодно продавать вместе с транспортными средствами, вам придется делать то, что вы всегда делаете

что вам мешает сделать класс достаточно абстрактным и свести различия к минимуму?

об этом же и идет речь: классы, которые вы придумали, находятся только в вашей голове, а значит из класса всегда можно сделать подкласс и ввести более общую категорию, которая избавит вас от большинства проблем, которые вы называете «обновлениями»

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

в моем примере ниже, с объектами интерфейса, алгоритмы обработки характеристик выделены в отдельные методы, которые в свою очередь организованы в соотвествии с характеристиками объектов — обьект 1, к которому не имеет отношение метод 2, никогда его и не увидит

по факту алгоритмы, методы — это те же свойства вашего товара, которыми вы можете управлять, как вам нужно — через общий интерфейс товаров, обращаясь к разным методам

кстати, те примеры полиморфизма, что можно быстро найти даже тут на хабре, как раз иллюстрируют неверный выбор hardcoded классов, которые невозможно перенести в другой проект :)

То есть вы предлагаете сделать один класс "Товар" и у него кучу атрибутов "летающий автомобиль", "плавающий автомобиль", "обычный автомобиль", "шкаф"? А как хранить атрибуты, специфичные для автомобиля и для шкафа и как задавать специфичную их обработку? Добавлять такую же кучу условий "if" в каждую процедуру? Один общий класс для всего это антипаттерн God-object. Это очень сложно в поддержке, и кроме того это не соответствует предметной области. Не говоря уже о том, что это явно не то, о чем пишет автор статьи.


Приведите пожалуйста конкретную реализацию с вашим подходом на примере операций покупки и продажи.


которая избавит вас от большинства проблем, которые вы называете «обновлениями»

Допустим, мы решили добавить понятие "vip-клиент" и давать таким клиентам скидку в 20%. До этого в предметной области никаких vip-клиентов не было. Как ваш подход поможет избежать "обновлений"?

сделайте разные функции и назначьте их в соответствии с категориями товаров, принадлежащих к одному классу товаров — никаких ифов не нужно, эти функции будут просто не доступны другим категориям

кстати, если бы вы рассуждали в ООП подходе, то вопроса об ифах у вас даже не должно было возникуть

попробуйте решить ваши задачи с товарами под названиями A, B, C etc, то есть в общем виде с общими категориями, не привязываясь к шкафам и автомобилям

по специфичным атрибутам ваши товары будут различаться, и то не факт, а по общим принадлежать к одному базовому классу

ваша система должна уметь обрабатывать любой товар: вряд ли кто-то строит системы по продаже одних конфет или одних велосипедов

у меня другие объекты, не товары, а элементы интерфейса; как вы понимаете их много разных и они все работают по-разному, но мы все свели к абстрактному понятию типа «объект» и двум базовым функциям этих объектов, и теперь имеем полную свободу в коммуникации между этими объектами с возможностью добавлять в этот класс любое количество типов с любой логикой и таскать эти объекты с той же логикой в любой проект

это было бы невозможно, если бы мы пошли по вашему пути и делали бы классы типа «vip-клиент», «банк», «транзакция» и каждый со своими атрибутами и методами, а потом думали бы, как поженить мышку с кошкой

думаю, что решение добавить понятие «vip-клиент» в класс товаров ошибочно, так как скидку дают не клиенту, а на товары, то есть скидка — просто еще один атрибут товара, причем даже не факт, что для этого надо делать еще один атрибут, потому что можно просто временно изменить цену — все зависит от того, насколько абстрактно вы можете смотреть на ваши товары и их характеристики

опять же красивые решения не возникают за 5 минут обсуждения в интернете, но это не значит, что они не возникают вообще

сделайте разные функции и назначьте их в соответствии с категориями товаров

И как же это сделать? Приведите пример.


у меня другие объекты, не товары, а элементы интерфейса

Ага, внезапно оказалось, что у вас очень ограниченная предметная область, в которой любой объект можно назвать элементом интерфейса.


с возможностью добавлять в этот класс любое количество типов

Опять же, приведите пример. Судя по описанию, у вас все-таки есть разные типы и наследование.


думаю, что решение добавить понятие «vip-клиент» в класс товаров ошибочно

А причем здесь класс товаров? Это был другой вопрос, про обновления.


то есть скидка — просто еще один атрибут товара

Нет, скидка это не атрибут товара, потому что один и тот же товар при разных условиях может продаваться с разной скидкой. "При покупке двух перчаток третья бесплатно".


опять же красивые решения не возникают за 5 минут обсуждения в интернете

Но вы же говорите, что у вас уже есть решение, которое вы проверили и потому его советуете.

извините, но предметная область не имеет никакого значения — ваша задача должна решаться в общем виде

когда вы попробуете это сделать, то сами легко сможете привести любой пример

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

скидки по факту не существует, есть новая цена товара, минимальное количество и сообщение по факту этой цены и количества, а эти атрибуты есть у всех категорий товаров

так что вы легко можете справиться с уже существующими атрибутами, останется добавить только дополнительную логику и выбирать ее для нужной категории товаров

у меня есть общее решение для абстрактных объектов, если ваша «предметная область» недостаточно абстрактна, то может понадобиться ввести более общий класс, что требует некоторого времени на анализ и поиск решения

То есть примеров, подтверждающих преимущество вашего подхода, у вас нет. Только слова о том, как это просто и удобно. Ок.

Надо создать модель объекта учета и отнести его к двум разным классам одновременно: к классу операций по продаже и к классу операций по покупке. В разных классах будет один атрибут «исполнитель», значения которого будут зависеть от того, какой класс мы рассматриваем: класс покупок, или класс продаж. И это неожиданно – оказывается, что значения атрибутов одного объекта учета могут зависеть от того, как мы классифицировали объект учета.

Если я правильно понял задачу, то к одному объекту учета относятся 2 "исполнительных" атрибута:


  • "исполнитель-продавец"
  • "исполнитель-покупатель"

Для класса "операция по покупке" атрибут "операция по покупке"."исполнитель" соответствует атрибуту "исполнитель-покупатель", для другого класса — "исполнитель-продавец":


  • "операция по покупке"."исполнитель" = "объект учета"."исполнитель-покупатель"
  • "операция по продаже"."исполнитель" = "объект учета"."исполнитель-продавец"

Т.е. вовсе не оказывается, что "значения атрибутов одного объекта учета могут зависеть от того, как мы классифицировали объект учета". Значения атрибутов объекта учета не зависят от классификации. От классификации зависит маппинг (сопоставление) атрибутов класса (значимых в контексте рассматриваемой задачи) и атрибутов объекта учета (всех доступных атрибутов объекта). Другое дело, что мы в целях экономии, как правило, маппим атрибуты один-в-один: "цвет" на "цвет", "массу" на "массу", поэтому и создается впечатление, что "атрибут класса" == "атрибут объекта". По значению — да, а по имени — не всегда.


Мне кажется достаточно спорным вывод "Классификация всегда субъективна и потому требует указания на субъект, проведшего классификацию." Нужна карта сопоставления атрибутов класса атрибутам объектов, чтобы два различных субъекта (и любая программа) провели классификацию объектов одинаково.


А в целом — весьма интересно наблюдать за вашей серией публикаций. Чувствуется биение мысли :)

Значения атрибута, конечно, не зависят от классификации. Они зависят от точки зрения на объект учета. Иванов ли смотрит, или Сидоров. Пример с классификацией — лишь промежуточный вывод на пути к основному.

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

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

код, если это скрижали на камне, — это объективная реальность. Но интерпретация этих знаков — дело субъективное. Кто-то скажет, что это — древние заклинания, кто-то — орнамент и тд

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


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


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


А как быть тогда в случае, если один человек правила создал, второй их изменил, а третий улучшил? Кого в этом случае указывать в качестве "субъекта, проведшего классификацию"?

Под классификацией я понимаю отнесение объекта учета к классу. Правила отнесения объекта учета к классу — не есть классификация. Вы говорите про код. Код — это информационный объект, требующий знания парадигмы (того, как его интерпретировать) После интерпретации получается образ. У каждого субъекта — свой образ интерпретации. Мы не знаем, как он выглядит, но знаем следствия из него — поведение человека. Исследуя поведение, мы можем сказать, того ли мы добивались, или не того. Мы не знаем, что в сознании, но можем пытаться воздействовать на поведение человека. Если код написан для машины, то это цепочка более длинная и требует подробного объяснения в виде отдельной статьи, которую я напишу позже.
Под классификацией я понимаю отнесение объекта учета к классу.

В таком случае совершенно верно "классификация — процесс субъективный". Т.к. при таком подходе возможно отнесение субъектом объекта учета, обладающего атрибутом "двигатель внутреннего сгорания", к классу "крокодилы Луизианы". Согласен, что в этом случае совершенно необходимо иметь "указание на субъект, проведший классификацию", дабы этому субъекту в следующий раз неповадно было.


Залез в wiki, посмотреть про классификацию — познавательно.

Sign up to leave a comment.

Articles