Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Абасс... обсудите рахитекурту

3762  1 2 3 4 5 6 7 8 все
alex445 патриот18.05.24 07:37
18.05.24 07:37 
Последний раз изменено 18.05.24 08:23 (alex445)

улыб

Драма в действиях - с прологом, эпилогом и интермедиями. Задача выделена жирным.


Всё просто - в классе есть свойства CurrentValue и MaxValue - они отвечают соответственно за два значения одного параметра. Сначала для простоты я написал так


public double CurrentValue { get; set; }
public double MaxValue { get; set; }


Теперь добавим условие для CurrentValue - оно не должно быть больше MaxValue, но не меньше 0. Для этого добавлю валидацию для CurrentValue, расписав его геттер и сеттер:


double currentValue;
public double CurrentValue
{
    get => currentValue;

    // если value вне диапазона, то вернуть ту или другую границу диапазона - смотря в какую сторону выходит
    set => currentValue = Math.Clamp(value, 0, MaxValue);
}


Далее усложняем. Хоть MaxValue и называется "максимальным", но оно тоже может изменяться, только менее часто, чем CurrentValue. Т.е. каждый раз, когда меняется MaxValue, CurrentValue должно быть пересчитано. Пришлось отказаться от автосвойств и расписать геттер и сеттер и для MaxValue:


double maxValue;
public double MaxValue
{
    get => maxValue;
    set
    {
        maxValue = value;
        CurrentValue = CurrentValue; // чтобы принудительно вызвать валидацию CurrentValue
    }
}


Т.к. maxValue уже установлено, то при валидации CurrentValue внутри сеттера MaxValue в этом месте, геттер MaxValue будет возвращать уже новое значение maxValue - т.е. тут всё законно.


Далее ещё усложняем. У меня CurrentValue и MaxValue на самом деле находятся в двух разных классах - один потомок другого. Один класс имеет лишь просто значения CurrentValue, а другой - добавляет MaxValue. Это потому, что есть параметры, которые меняются часто между минимумом и максимумом, а есть, которые просто меняются, и при этом нечасто. Где просто меняются, достаточно одного значения параметра - я назвал его не текущим, а максимальным (MaxValue ), а где часто - там нужно ещё и текущий - CurrentValue. Т.е. пока я просто разнёс их в разные классы:


public class Param
{
    double maxValue;
    public double MaxValue
    {
        get => maxValue;
        set
        {
            maxValue = value;
            CurrentValue = CurrentValue;
        }
    }
}
public class ParamVolatile : Param
{
    double currentValue;
    public double CurrentValue
    {
        get => currentValue;
        set => currentValue = Math.Clamp(value, 0, MaxValue);
    }
}


Тут загвоздка - класс Param не знает о CurrentValue из ParamVolatile. На помощь пришло переопределение свойства - мы оставим MaxValue в классе Param девственно чистым, не знающим о существовании всяких ветренных и непостоянных ParamVolatile, а ParamVolatile будет иметь своё собственное "видение" для MaxValue - с блекджеком и так далее:


public class Param
{
    double maxValue;
    public virtual double MaxValue
    {
        get => maxValue;
        set => maxValue = value;
    }
}
public class ParamVolatile : Param
{
    double maxValue;
    public override double MaxValue
    {
        get => maxValue;
        set
        {
            maxValue = value;
            CurrentValue = CurrentValue;
        }
    }
    double currentValue;
    public double CurrentValue
    {
        get => currentValue;
        set => currentValue = Math.Clamp(value, 0, MaxValue);
    }
}


Но зачем нам тогда наследование, если у нас ParamVolatile имеет своё собственное своство MaxValue? А это для заморочек с приведениями типов. Надо, короче. Но всё же мы можем кое-что упростить. Например, зачем нам два приватных поля maxValue в двух разных классах? Это же по сути два разных значения, никак не связанных. А нам по идее нужно лишь одно. Давайте уберём это поле из класса ParamVolatile и заставим использовать этот класс поле из Param - через свойство MaxValue класса Param. Код изменённого класса ParamVolatile - поменялось лишь свойство MaxValue и мы убрали дублирующее поле maxValue


public class ParamVolatile : Param
{    
    public override double MaxValue
    {
        get => base.MaxValue;
        set
        {
            base.MaxValue = value;
            CurrentValue = CurrentValue;
        }
    }
    double currentValue;
    public double CurrentValue
    {
        get => currentValue;
        set => currentValue = Math.Clamp(value, 0, MaxValue);
    }
}


Ну и добавим валидацию и для MaxValue базового класса - а то чё это оно у нас без валидации, зря чтоли от автосвойства отказывался. Просто обозначу валидирующую функцию и приведу окончательный код обоих классов:


public class Param
{
    double maxValue;
    public virtual double MaxValue
    {
        get => maxValue;
        set => maxValue = ValidateMaxValue(value);
    }
}
public class ParamVolatile : Param
{
    public override double MaxValue
    {
        get => base.MaxValue;
        set
        {
            base.MaxValue = value;
            CurrentValue = CurrentValue;
        }
    }
    double currentValue;
    public double CurrentValue
    {
        get => currentValue;
        set => currentValue = Math.Clamp(value, 0, MaxValue);
    }
}


Теперь у нас по идее есть валидация в базовом классе для свойства MaxValue, которая та же самая используется и в производном классе для этого же переопределённого свойства, и плюс специальная механика для свойства CurrentValue в производном классе, завязанная на изменение свойства MaxValue базового класса. Потестил - вроде работает.


Можно ли сделать лучше для описанной задачи (напомню - выделено жирным)? Может что с интерфейсами намутить? Кода не так уж много, и вроде вылизан, а интерфейсы лишь добавят лапшы, нет? Меня здесь смущает в основном запись CurrentValue = CurrentValue для принудительной валидации CurrentValue. В комментах к коду я написал, почему так делаю, но вроде можно вместо такой записи (присваивание самому себе) и повторить код сеттера CurrentValue:


currentValue = Math.Clamp(value, 0, MaxValue);


Но это же повтор кода! Страшное нарушение какого-то там принципа каких-то там шибко умных старпёров. Короче, табу. Поэтому решил, что просто присвоить свойство самому себе выйдет дешевле. Комментиком сверху пригладил, зачем так сделал, и зашибись.


Сразу говорю, что не юзал разные валидирующие атрибуты типа RangeAttribute, т.к. они ничего не валидируют, а лишь задают валидирующие значения и сообщения об ошибках - для них надо писать свою функцию валидации, которая вытаскивает из этих атрибутов их значения (через рефлексию, ага) и производит собственно валидацию. Для некоторых фреймворков типа ASP.NET MVC это уже написано и работает под капотом, но для своего кода надо писать самому. Зачем так сложно, если эти значения у меня уже в готовых свойствах, как и валидация.

#1 
alex445 патриот18.05.24 08:16
NEW 18.05.24 08:16 
в ответ alex445 18.05.24 07:37, Последний раз изменено 18.05.24 08:25 (alex445)

Кстати, пошарился по МСДНу и Стековерфлоу - разбираются всякие переопределения, сокрытия свойств, но нигде нет примера переопределениям свойства с его полем - нужно ли поле тоже "переопределять". Да, поля нельзя переопределять, но как их использовать в переопределённом свойстве? Все примеры переопределения - лишь для автосвойств. Например. Или здесь темку как-то заболтали, т.к. автор был неконкретен и сразу скатился в "или... или... или...". Или все статьи про полиморфизм, про переопределение, про использование переопределения или сокрытия - там везде разбираются лишь простейшие примеры, типа возврата константы или переопределения свойства вообще без поля и кода, или лишь примеры с методами, а не свойствами. И ни одного смешанного примера, где бы возвращалось поле поддержки (backing field). То, что для свойств с полем в базовом классе, чтобы использовать это поле в классе-потомке, нужно вызвать базовую версию геттера или сеттера, которая работает с базовым полем (а не заводить второе поле для класса-потомка) - нигде не показывается. А я вот в своём примере выше это разобрал. А вот если хочешь скрыть свойство, тогда да - лучше завести второе поле для класса-потомка.


Но это так, дополнение к моему первому посту. Попробуйте какого-нибудь сеньёра поспрашивать про не очень стандартный пример не из букваря - посыпится наверняка. ))

Если привык к самым стандартным конструкциям и годами только их и встречал, а потом встретил чуть более не такое - будет сидеть и репу чесать, хотя "10+ лет опыта, ценный специалист и заслуженный сеньёр". ))

#2 
alex445 патриот18.05.24 08:30
NEW 18.05.24 08:30 
в ответ alex445 18.05.24 08:16, Последний раз изменено 18.05.24 08:31 (alex445)

ИЧСХ, вроде спрашиваешь поисковик конкретный и довольно короткий вопрос, типа

"C# override property with the same backing field"

или

"C# override property example"

И тебе выдаёт либо всякую муть, либо простейшие примеры переопределения без использования поля поддержки базового класса. Гугл, Майкрософт, мать вашу, вы своих долбаных ИИ чему обучаете, если они ни ответа дать не могут (что их поисковики, что их ИИ чат боты), ни маршрут нормальный в навигаторе построить - самые насущные вопросы. Зато всякую херню делать годами и десятилениями, инклюзивность и прочая смузёво-скриптизёрская параша - это хлебом не корми.

#3 
Срыв покровов патриот18.05.24 13:19
NEW 18.05.24 13:19 
в ответ alex445 18.05.24 08:30

как выглядит функция ValidateMaxValue?


Последний пример наверное будет работать, пока у класса Param только один наследник.
Если ты присвоишь новое значение MaxValue во втором наследнике, то первый же об этом ничего не узнает?

#4 
alex445 патриот18.05.24 13:39
NEW 18.05.24 13:39 
в ответ Срыв покровов 18.05.24 13:19, Последний раз изменено 18.05.24 13:41 (alex445)
как выглядит функция ValidateMaxValue?

В общем виде так

double ValidateMaxValue(double incomingValue)


А в реальности сложнее - у класса Param есть ещё свойство ParamType, которое тоже передаётся в функцию валидации, и в зависимости от него валидируется. Но это детали моей реализации для моего случая. В общем же виде я выше написал.


Последний пример наверное будет работать, пока у класса Param только один наследник.
Если ты присвоишь новое значение MaxValue во втором наследнике, то первый же об этом ничего не узнает?

А зачем двум разных наследникам - т.е. двум разным параллельным классам - знать, что происходит в параллельном классе? Это же будут разные объекты, у которых из общего лишь базовый класс. Или какой пример наследования вы имели ввиду - уже не от Param, а от ParamVolatile?


Пока у меня действительно лишь один наследник от Param, и всё вроде работает.

#5 
alex445 патриот18.05.24 13:45
NEW 18.05.24 13:45 
в ответ alex445 18.05.24 13:39, Последний раз изменено 18.05.24 13:47 (alex445)

По-моему, у меня как-то запутана валидация - она раздроблена между свойствами: вот эта запись это по сути тоже валидация


set => currentValue = Math.Clamp(value, 0, MaxValue);


А у меня видно же, что свойства связанные - одно от другого зависит. По идее, связанные свойства должны валидироваться одной функцией валидации, которая учитывает значение сразу всех связанных свойств. Логично? Этот описанный мной вариант масштабируется на сколько угодно свойств - просто вызываешь одну функцию валидации на любое изменение любого свойства из группы зависимых. А вариант в моём первом посте масштабировать трудно - нужно переписать много кода и не ошибиться в заимных зависимостях.

#6 
AlexNek патриот18.05.24 13:57
AlexNek
NEW 18.05.24 13:57 
в ответ alex445 18.05.24 07:37

ну, для начала слишком много букафф смущ.

И опять что то из мира извращений.

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

Отчего не сделать всё требуемую логику в одном объекте, а после пользовать его где надо?

#7 
AlexNek патриот18.05.24 14:05
AlexNek
NEW 18.05.24 14:05 
в ответ alex445 18.05.24 07:37
CurrentValue = CurrentValue; // чтобы принудительно вызвать валидацию CurrentValue

Сразу не проходит review смущ нужна валидация, значит делаем, а не вызываем side эффект с комментарием.


#8 
alex445 патриот18.05.24 14:07
NEW 18.05.24 14:07 
в ответ AlexNek 18.05.24 13:57, Последний раз изменено 18.05.24 14:08 (alex445)

Это я ещё до фабрики фабрик не добрался - так, на уровне букваря ковыряю. )))

Просто писал, как придумывал такую архитектуру, по шагам.


Что значит "вся логика в одном объекте"? Есть базовый класс, которого достаточно для многих объектов. И есть наследник, который расширяет базовый. У каждого своя валидация, но в наследнике использовать валидацию базового класса было бы неплохо.


Как вариант, я могу сделать свойство MaxValue в наследнике не override, а new, со своим собственным полем поддержки. И валидацию базового класса для этого свойства вызвать методом ValidateMaxValue, а не через вызов родительского варианта сеттера base.MaxValue = value;

#9 
alex445 патриот18.05.24 14:15
NEW 18.05.24 14:15 
в ответ alex445 18.05.24 14:07, Последний раз изменено 18.05.24 14:16 (alex445)

Сделал с new и отдельным вызовом валидирующего метода ValidateMaxValue для потомка. И ещё вынес валидацию CurrentValue тоже в отдельный метод. Вроде, так лучше


public class Param
{
    double maxValue;
    public double MaxValue
    {
        get => maxValue;
        set => maxValue = ValidateMaxValue(value);
    }

    protected double ValidateMaxValue(double value) => ...
}

public class ParamVolatile : Param
{
    double maxValue;
    public new double MaxValue
    {
        get => maxValue;
        set
        {
            maxValue = ValidateMaxValue(value);
            currentValue = ValidateCurrentValue(CurrentValue, 0, maxValue);
        }
    }

    double currentValue;
    public double CurrentValue
    {
        get => currentValue;
        set => currentValue = ValidateCurrentValue(CurrentValue, 0, MaxValue);
    }

    ValidateCurrentValue(double value, double min, double max) => Math.Clamp(value, min, max);
}


#10 
AlexNek патриот18.05.24 14:15
AlexNek
NEW 18.05.24 14:15 
в ответ alex445 18.05.24 14:07
как придумывал такую архитектуру,

вообще то называть это архитектурой у меня язык не поворачивается. Слишком мелко.

Типа в озере на доске катался, а после говорить как на море тренировался.


Что значит "вся логика в одном объекте"?

Ну вот же описан объект в нём и должно быть всё


public double CurrentValue { get; set; }
public double MaxValue { get; set; }
#11 
alex445 патриот18.05.24 14:19
NEW 18.05.24 14:19 
в ответ AlexNek 18.05.24 14:15, Последний раз изменено 18.05.24 14:29 (alex445)
Что значит "вся логика в одном объекте"?
Ну вот же описан объект в нём и должно быть всё



public double CurrentValue { get; set; }
public double MaxValue { get; set; }

Нет, базовый класс тоже вполне самодостаточный - можно создавать его объекты отдельно. Но часть его функциональности я бы хотел иметь в потомке. Гляньте мой последний вариант. Мне в нём не нравится только то, что свойство MaxValue в потомке почти полностью повторяет родителя. Может, вернуться к virtual-override и вызову базового сеттера, оставив лишь валидирующие функции?


public class Param
{
    double maxValue;
    public virtual double MaxValue
    {
        get => maxValue;
        set => maxValue = ValidateMaxValue(value);
    }

    double ValidateMaxValue(double value) => ...
}

public class ParamVolatile : Param
{
    public override double MaxValue
    {
        get => base.MaxValue;
        set
        {
            base.MaxValue = value;
            currentValue = ValidateCurrentValue(CurrentValue, 0, MaxValue);
        }
    }

    double currentValue;
    public double CurrentValue
    {
        get => currentValue;
        set => currentValue = ValidateCurrentValue(CurrentValue, 0, MaxValue);
    }

    ValidateCurrentValue(double value, double min, double max) => Math.Clamp(value, min, max);
}
#12 
Срыв покровов патриот18.05.24 14:29
NEW 18.05.24 14:29 
в ответ alex445 18.05.24 13:39
А зачем двум разных наследникам - т.е. двум разным параллельным классам - знать, что происходит в параллельном классе?

Да, это я что-то затупил.

#13 
Срыв покровов патриот18.05.24 14:30
NEW 18.05.24 14:30 
в ответ alex445 18.05.24 14:19
Гляньте мой последний вариант. Мне в нём не нравится только то, что свойство MaxValue в потомке почти полностью повторяет родителя

там же свойство базового класса вообще не используется.

#14 
alex445 патриот18.05.24 14:35
NEW 18.05.24 14:35 
в ответ Срыв покровов 18.05.24 14:30, Последний раз изменено 18.05.24 14:42 (alex445)

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


#15 
AlexNek патриот18.05.24 14:43
AlexNek
NEW 18.05.24 14:43 
в ответ alex445 18.05.24 14:19
Нет, базовый класс тоже вполне самодостаточный

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

Я бы попытался бы вначале сформулировать что хочется. Иногда помогает себе же.


оставив лишь валидирующие функции?

Это кстати не совсем валидирующие функции. Валидирующие функции имеют право возвращать результат: валидный / невалидный объект

#16 
alex445 патриот18.05.24 14:46
NEW 18.05.24 14:46 
в ответ AlexNek 18.05.24 14:43, Последний раз изменено 18.05.24 14:47 (alex445)
оставив лишь валидирующие функции?
Это кстати не совсем валидирующие функции. Валидирующие функции имеют право возвращать результат: валидный / невалидный объект

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

#17 
alex445 патриот18.05.24 14:49
NEW 18.05.24 14:49 
в ответ alex445 18.05.24 14:35, Последний раз изменено 18.05.24 14:52 (alex445)

Мне в последнем варианте (с зелёным) не нравится, что я два раза вызываю один и тот же код для currentValue: currentValue = ValidateCurrentValue(...). И всё лишь ради того, чтобы не было "странного" CurrentValue = CurrentValue, которое смотрится компактнее и лаконичнее. Но если вся валидация будет внутри метода ValidateCurrentValue, без добавок снаружи него, то вроде нормально - не придётся вносить одинаковые изменения в двух разных местах.

#18 
AlexNek патриот18.05.24 14:51
AlexNek
NEW 18.05.24 14:51 
в ответ alex445 18.05.24 14:46
У меня они больше корректирующие - принудительно корректируют значение

ну вот именно, поэтому название валидация сбивает с толку.

#19 
alex445 патриот18.05.24 14:54
NEW 18.05.24 14:54 
в ответ AlexNek 18.05.24 14:51, Последний раз изменено 18.05.24 14:56 (alex445)


У меня они больше корректирующие - принудительно корректируют значение
ну вот именно, поэтому название валидация сбивает с толку.

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


Когда вы даёте юзеру просто текстовое поле, а нужно получить от него числа, то вы валидируете текст через парсинг, потом сравнение на диапазоны и прочее. А можно сразу в контрол встроить возможность ввода лишь цифр и принудительное выставление введённых чисел по границам, если числа выходят за эти границы. И это всё разные виды валидации, только одна - более многословная и требует кучу кастомного кода, а другая - более автоматизированная, со многими вещами, работающими из коробки (если этот контрол кто-то другой написал).

#20 
AlexNek патриот18.05.24 14:57
AlexNek
NEW 18.05.24 14:57 
в ответ alex445 18.05.24 14:49
что я два раза вызываю один и тот же код для currentValue

не вижу особых проблем в этом


Мне больше не нравится, что проперти имеют логику.

#21 
alex445 патриот18.05.24 14:58
NEW 18.05.24 14:58 
в ответ alex445 18.05.24 14:54

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

#22 
alex445 патриот18.05.24 14:59
NEW 18.05.24 14:59 
в ответ AlexNek 18.05.24 14:57
что я два раза вызываю один и тот же код для currentValue

не вижу особых проблем в этом

Мне больше не нравится, что проперти имеют логику.

По классике в пропертях вполне делается валидация. Просто у меня зависимые проперти, поэтому некоторые из них валидируют не только себя, а и другие проперти. А проперти совсем без логики не имеют смысла.

#23 
AlexNek патриот18.05.24 15:02
AlexNek
NEW 18.05.24 15:02 
в ответ alex445 18.05.24 14:54
Просто вы привыкли, что валидация, это когда юзеру сообщаешь, а он исправляет.

не обязательно. Просто имя ожидается в этом случае другое. Типа: GetValidObject

К тому же "по параметрам" можно сделать вывод что функция должна быть статической.

#24 
AlexNek патриот18.05.24 15:08
AlexNek
NEW 18.05.24 15:08 
в ответ alex445 18.05.24 14:59
А проперти совсем без логики не имеют смысла.

ну да public поле будет гораздо лучше спок

Но данном случае "SetValue()" было бы более наглядным.

#25 
alex445 патриот18.05.24 15:34
NEW 18.05.24 15:34 
в ответ AlexNek 18.05.24 15:08, Последний раз изменено 18.05.24 15:35 (alex445)
А проперти совсем без логики не имеют смысла.
ну да public поле будет гораздо лучше спок

В Unity 3D всё на публичных полях делается, что касается работы с их редактором:


public string myName = "none";


улыб

Это для облегчения сериализации, как они объясняют.

#26 
Срыв покровов патриот18.05.24 16:00
NEW 18.05.24 16:00 
в ответ alex445 18.05.24 14:35
Ну да - в этом и смысла сокрытия.

так в каком из них тогда хранится текущее значение?

#27 
alex445 патриот18.05.24 16:07
NEW 18.05.24 16:07 
в ответ Срыв покровов 18.05.24 16:00

В варианте с new я отказываюсь от механики родительского свойства и пишу свою миханику - т.е. хранится в поддерживающем поле потомка. Тут мне нужно лишь свойство с тем же именем. В варианте с override - в поддерживающем поле родителя, но тогда мне не нужно отдельное поле в потомке.

#28 
AlexNek патриот18.05.24 18:13
AlexNek
NEW 18.05.24 18:13 
в ответ alex445 18.05.24 15:34
В Unity 3D всё на публичных полях делается

Если кому нравится играться в навозе пусть играется. бебе

#29 
Срыв покровов патриот18.05.24 18:24
NEW 18.05.24 18:24 
в ответ alex445 18.05.24 16:07

зачем тебе в варианте с new вообще родительское свойство?

#30 
alex445 патриот18.05.24 19:40
NEW 18.05.24 19:40 
в ответ Срыв покровов 18.05.24 18:24

Пушо клиентский код вызывает свойство с этим именем у объектов родительского и потомкового класса одинаково. Но вариант с new мне не нравится - я буду использовать с override.

#31 
alex445 патриот18.05.24 19:43
NEW 18.05.24 19:43 
в ответ AlexNek 18.05.24 18:13
В Unity 3D всё на публичных полях делается

Если кому нравится играться в навозе пусть играется.

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

#32 
AlexNek патриот18.05.24 19:51
AlexNek
NEW 18.05.24 19:51 
в ответ alex445 18.05.24 19:43

А причём вообще тут Unity 3D? Как хотят пусть так и делают.

#33 
alex445 патриот18.05.24 19:52
NEW 18.05.24 19:52 
в ответ AlexNek 18.05.24 14:05, Последний раз изменено 18.05.24 19:54 (alex445)
вообще то называть это архитектурой у меня язык не поворачивается. Слишком мелко.
Типа в озере на доске катался, а после говорить как на море тренировался.

Нифига, я уже морской волк! ))


CurrentValue = CurrentValue; // чтобы принудительно вызвать валидацию CurrentValue
Сразу не проходит review смущ нужна валидация, значит делаем, а не вызываем side эффект с комментарием.


А те, кто ревью делают, понимают хоть, что происходит и зачем это нужно, или тупо по дядибобовским методичкам шпарят? )))

А то разное бывает. "На ноль делить нельзя" - иногда можно. "Поля не должны быть публичными" - если надо, то можно. "Земля вращается вокруг Солнца" - а мой личный опыт подсказывает, что это Солнце вращается вокруг Земли.

#34 
alex445 патриот18.05.24 19:53
NEW 18.05.24 19:53 
в ответ AlexNek 18.05.24 19:51
А причём вообще тут Unity 3D? Как хотят пусть так и делают.

Ну, я в принципе более-менее подходящий ответ на свой вопрос нашёл. Теперь можно и побарагозить. ))

#35 
AlexNek патриот18.05.24 19:58
AlexNek
NEW 18.05.24 19:58 
в ответ alex445 18.05.24 19:52
понимают хоть, что происходит и зачем это нужно

Может все по разному понимают смущ

Хотя даже и понимать не нужно:

1. строка без коммента выглядит бессмысленной

2. коммент говорит о том, что мы используем side эффект


Вполне достаточно для зловония

#36 
AlexNek патриот18.05.24 20:04
AlexNek
NEW 18.05.24 20:04 
в ответ alex445 18.05.24 19:52
а мой личный опыт подсказывает,

Если личный опыт сильно расходится с устоявшимися нормами, то требуется дополнительное исследование.

При этом, в настоящее время, вероятность того, что личный опыт правильнее устоявшихся норм довольна мала.

#37 
alex445 патриот18.05.24 20:33
NEW 18.05.24 20:33 
в ответ AlexNek 18.05.24 19:58
Вполне достаточно для зловония

Но-но, это тонкая оптимизация!

#38 
AlexNek патриот18.05.24 20:53
AlexNek
NEW 18.05.24 20:53 
в ответ alex445 18.05.24 20:33

угу, духи: perdon la couture

#39 
anly патриот19.05.24 19:15
anly
NEW 19.05.24 19:15 
в ответ alex445 18.05.24 07:37

начал читать и вспомнил Библию:


Посрамились мудрецы, смутились и запутались в сеть: вот, они отвергли слово Господне; в чем же мудрость их?
Иеремия 8:9 — Иер 8:9

улыб

Как то слишком много умного в простейшей задаче.



Проклят нарушающий межи ближнего своего (Втор.27:17)
#40 
alex445 патриот19.05.24 19:39
NEW 19.05.24 19:39 
в ответ anly 19.05.24 19:15, Последний раз изменено 19.05.24 19:48 (alex445)

Я предложил предложить своё предложение для этой "простейшей задачи". Никто не захотел. Напомню задачу:


  1. текущее и максимальное значения одного параметра разнесены на два класса, но т.к. это один параметр, то они связаны - текущее зависит от максимального (текущее не может быть больше максимального), но не наоборот
  2. для каждого значения своя валидация - с учётом первого пункта связности двух параметров


Разнесены на 2 класса, т.к. составной параметр построен на базе простого, состоящего из одного значения - использует его инфраструктуру (поля, свойства, методы и т.д.) и валидацию. Всё просто. Не какое-нибудь многостраничное техзадание. Можно на собесах этим мучить. Типа задачка на полчаса. От силы час. Два класса, два свойства - смотрите, не запутайтесь, "сеньёры и ценные специалисты с ниипацо стажем". )))

#41 
AlexNek патриот19.05.24 20:44
AlexNek
NEW 19.05.24 20:44 
в ответ alex445 19.05.24 19:39

А в чём то сейчас проблема? Как я понял подходящее решение уже найдено.


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

#42 
AlexNek патриот19.05.24 20:48
AlexNek
NEW 19.05.24 20:48 
в ответ alex445 19.05.24 19:39
Разнесены на 2 класса, т.к. составной параметр построен на базе простого... разнесены на два класса, но т.к. это один параметр, то они связаны

Единственный вопрос - нафига разнесены?


#43 
alex445 патриот19.05.24 21:13
NEW 19.05.24 21:13 
в ответ AlexNek 19.05.24 20:48, Последний раз изменено 19.05.24 21:15 (alex445)
Единственный вопрос - нафига разнесены?

Я уже 10 раз написал - функционал максимального значения у составного параметра точно такой же, как просто значения у простого параметра. Т.е. в составном простое значение используется как максимальное, и добавлено текущее значение.


Ребята, что с вами, это просто два жалких класса с парой куцых свойств на двоих же. Чего вы их так испугались?.. Ну хорошо, вам не нравится наследование. Тогда что? В нашем ООПешном загончике не так много вариантов для комбинирования - наследование, включение, пачка статических методов... Я что-то важное упустил?


Может, будем городить интерфейсы или фабрику фабрик? Два-то класса это слишком сложно, а вот инжекция фабрики на интерфейсах - это пахнет месяцем мозгового штурма, километров тестов, и всё это на сеньёрских зарплатах. ))

#44 
AlexNek патриот19.05.24 21:17
AlexNek
NEW 19.05.24 21:17 
в ответ alex445 19.05.24 21:13
функционал максимального значения у составного параметра точно такой же, как просто значения у простого параметра

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

#45 
AlexNek патриот19.05.24 21:52
AlexNek
NEW 19.05.24 21:52 
в ответ alex445 19.05.24 21:13
функционал максимального значения у составного параметра точно такой же, как просто значения у простого параметра

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

public double CurrentValue { get; set; }
public double MaxValue { get; set; }

Так что

если у нас есть параметр1 Value, то он должен иметь CurrentValue и MaxValue

и есть параметр2 MaxValue, то и он должен иметь CurrentValue и MaxValue


В данном случае подобного не наблюдается.

#46 
Срыв покровов патриот19.05.24 22:58
NEW 19.05.24 22:58 
в ответ alex445 19.05.24 19:39

Вангую, что такого есть какой-нибудь пэттерн типа Subscriber или Notifier.

#47 
alex445 патриот20.05.24 01:37
NEW 20.05.24 01:37 
в ответ AlexNek 19.05.24 21:52
функционал максимального значения у составного параметра точно такой же, как просто значения у простого параметра

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

public double CurrentValue { get; set; }
public double MaxValue { get; set; }

Так что

если у нас есть параметр1 Value, то он должен иметь CurrentValue и MaxValue

и есть параметр2 MaxValue, то и он должен иметь CurrentValue и MaxValue

В данном случае подобного не наблюдается.

У нас есть просто параметры, которые относительно постоянны (в пределах определённого времени), и быстро изменяющиеся параметры, у которых значение может быстро изменяться между нулём и определённым значением - эти последние я называю составными, т.к. состоят из текущего и этого определённого. Это определённое значение не есть максимальное значение вообще, т.к. оно тоже может изменяться, но не так быстро, как текущее, а так же, как и значение обычного параметра. Но для удобства я называю его максимальным. А чтобы использовать общий класс (с общей функциональностью) для этого значения, я называю его MaxValue и в классе обычного параметра.


Я бы мог поменять MaxValue на просто Value - тогда название значения в обычном параметре стало бы более осмысленным, но в составном - менее, т.к. CurrentValue меняется от 0 до Value. Но тут либо то, либо другое - где-то название будет не очень соответствовать.


Суть-то не в названиях, а в реализации.

#48 
alex445 патриот20.05.24 01:41
NEW 20.05.24 01:41 
в ответ Срыв покровов 19.05.24 22:58
Вангую, что такого есть какой-нибудь пэттерн типа Subscriber или Notifier.

"Ты чё умничаешь, ты пальцем покажи!"


А этот паттерн проще, чем мои пару десятков строчек, из которых треть - скобки?

#49 
AlexNek патриот20.05.24 11:15
AlexNek
NEW 20.05.24 11:15 
в ответ alex445 20.05.24 01:37
У нас есть просто параметры, которые относительно постоянны (в пределах определённого времени), и быстро изменяющиеся параметры

Опять что то не из той оперы. Это скорее к расположению элементов ввода. Что то еще вы батенька скрываете спок


Я бы мог поменять MaxValue на просто Value - тогда название значения в обычном параметре стало бы более осмысленным, но в составном - менее

Это сразу говорит о том, что что то не в порядке.


Суть-то не в названиях, а в реализации.

реализация дело вторичное, главное "модель системы".

#50 
AlexNek патриот20.05.24 11:18
AlexNek
NEW 20.05.24 11:18 
в ответ alex445 20.05.24 01:41

А отчего, кстати у Param MaxValue отсуствует MaxValue смущ

#51 
alex445 патриот20.05.24 11:32
NEW 20.05.24 11:32 
в ответ AlexNek 20.05.24 11:15, Последний раз изменено 20.05.24 11:36 (alex445)
У нас есть просто параметры, которые относительно постоянны (в пределах определённого времени), и быстро изменяющиеся параметры
Опять что то не из той оперы. Это скорее к расположению элементов ввода. Что то еще вы батенька скрываете спок

Это не элементы ввода, а элементы отображения. Есть параметры, которые относительно постоянные и описываются одним числом, а есть которые изменяются быстро (расходуются и пополняются) - им нужно два числа - максимальное значение и текущее.


Например, скорость обозначается параметром с одним числом (текущая скорость), а топливо - параметром с двумя числами (макс. топлива и текущий объём). Чтобы не делать два совсем разных типа параметров, сделал базовый тип с одним значением, и второй унаследовал от него, добавив текущее значение.

#52 
alex445 патриот20.05.24 11:37
NEW 20.05.24 11:37 
в ответ AlexNek 20.05.24 11:18, Последний раз изменено 20.05.24 11:40 (alex445)
А отчего, кстати у Param MaxValue отсуствует MaxValue

Где отсутствует? У меня присутствует. Это у ParamVolatile отсутствует поле maxValue, т.к. используется поле базового класса через свойство базового класса. У ParamVolatile свойство MaxValue это обёртка над базовым одноимённым свойством.

#53 
AlexNek патриот20.05.24 11:45
AlexNek
NEW 20.05.24 11:45 
в ответ alex445 20.05.24 11:37
у Param MaxValue отсуствует MaxValue ... Где отсутствует? У меня присутствует.


"Ты чё умничаешь, ты пальцем покажи!" бебе

#54 
AlexNek патриот20.05.24 11:48
AlexNek
NEW 20.05.24 11:48 
в ответ alex445 20.05.24 11:32
Чтобы не делать два совсем разных типа параметров, сделал базовый тип

во это как раз то, что дедушка Мюллер и должен был узнать в подвале спок


Есть набор различных параметров и им нужен базовый тип.

#55 
alex445 патриот20.05.24 12:15
NEW 20.05.24 12:15 
в ответ AlexNek 20.05.24 11:48
Есть набор различных параметров и им нужен базовый тип.

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

#56 
alex445 патриот20.05.24 12:18
NEW 20.05.24 12:18 
в ответ AlexNek 20.05.24 11:45
у Param MaxValue отсуствует MaxValue ... Где отсутствует? У меня присутствует.

"Ты чё умничаешь, ты пальцем покажи!" бебе

Пройдите по моей ссылке и попробуйте отследить выполнение кода, если присвоить свойству MaxValue объекта ParamVolatile какое-нибудь значение. Обратите внимание на


base.MaxValue = value;
#57 
AlexNek патриот20.05.24 12:21
AlexNek
NEW 20.05.24 12:21 
в ответ alex445 20.05.24 12:15
Только базовый тип у меня не бесполезный абстрактный

Это уже следующий этап, тогда.


Пока что видно что всем параметрам нужно "double Value"

#58 
AlexNek патриот20.05.24 12:22
AlexNek
NEW 20.05.24 12:22 
в ответ alex445 20.05.24 12:18
объекта ParamVolatile

речь об объекте Param

#59 
alex445 патриот20.05.24 13:20
NEW 20.05.24 13:20 
в ответ AlexNek 20.05.24 12:21
Только базовый тип у меня не бесполезный абстрактный

Это уже следующий этап, тогда.

Пока что видно что всем параметрам нужно "double Value"

Переименуем MaxValue в Value в обоих классах. Лучше стало?

#60 
Срыв покровов патриот20.05.24 13:24
NEW 20.05.24 13:24 
в ответ AlexNek 20.05.24 11:18
А отчего, кстати у Param MaxValue отсуствует MaxValue смущ

😵‍💫

#61 
alex445 патриот20.05.24 13:24
NEW 20.05.24 13:24 
в ответ AlexNek 20.05.24 12:22
объекта ParamVolatile

речь об объекте Param

Ну так в Param есть MaxValue, играющее роль и Value. Если значение одно, то какая разница, как его назвать? А мне удобно назвать для совместимости с классом-наследником. Или назову его Value - тогда будет удобно в базовом классе, а в наследнике придётся приписать коммент, что Value играет роль максимального значения.


Если же я введу третью сущность (Value, MaxValue, CurrentValue), то это будет дублирование, т.к. Value и MaxValue играют одну роль и одинаково валидируются, и с ними одинаково обращаются клиенты классов Param и ParamVolatile. А вот клиентам будет путаница - все алгоритмы нужно перестроить, чтобы Value и MaxValue воспринимались одинаково. Проще в классах Param и ParamVolatile ввести одну условность и откомментить её, чем перелопачивать алгоритмы.

#62 
alex445 патриот20.05.24 13:25
NEW 20.05.24 13:25 
в ответ Срыв покровов 20.05.24 13:24

Да он описался. В хорошем смысле. )))

#63 
AlexNek патриот20.05.24 13:26
AlexNek
NEW 20.05.24 13:26 
в ответ alex445 20.05.24 13:20
Переименуем MaxValue в Value в обоих классах. Лучше стало?

Нет конечно. Не следует торопиться. У нас пока еще нет реализации. Обсуждаются только проблемы "модели".


Похоже для Value нам еще нужен еще UpperLimit, так как LowerLimit всегда 0. /Специально выбрал какое то другое имя чтобы не путатся/

#64 
AlexNek патриот20.05.24 13:28
AlexNek
NEW 20.05.24 13:28 
в ответ Срыв покровов 20.05.24 13:24

ну так уж в оригинале, сорри

ограничения для MaxValue у класса Param

#65 
AlexNek патриот20.05.24 13:30
AlexNek
NEW 20.05.24 13:30 
в ответ alex445 20.05.24 13:24
Ну так в Param есть MaxValue, играющее роль и Value

как я понял для каждого значения нужно еще и ограничение или нет?

#66 
AlexNek патриот20.05.24 13:31
AlexNek
NEW 20.05.24 13:31 
в ответ alex445 20.05.24 13:25

Не, не хотел вводить новые названия, вот же есть для всех параметров

public double CurrentValue { get; set; }
public double MaxValue { get; set; }
#67 
AlexNek патриот20.05.24 14:29
AlexNek
NEW 20.05.24 14:29 
в ответ alex445 20.05.24 13:24
А вот клиентам будет путаница - все алгоритмы нужно перестроить,

то есть есть еще одно ограничение о котором умолчали?


Ну если идет речь о правке Big ball of mud, то и обсуждать особо нечего.

#68 
alex445 патриот20.05.24 15:59
NEW 20.05.24 15:59 
в ответ AlexNek 20.05.24 13:26, Последний раз изменено 20.05.24 16:05 (alex445)
Похоже для Value нам еще нужен еще UpperLimit, так как LowerLimit всегда 0. /Специально выбрал какое то другое имя чтобы не путатся/

как я понял для каждого значения нужно еще и ограничение или нет?

Да. Любой Param или ParamVolatile имеет свой скажем так глобальный максимум и минимум, который они не могут превышать. И эти максимум и минимум я храню в валидирующем коде, а не в самих Param или ParamVolatile. А у ParamVolatile есть ещё текущий максимум, который он не может превышать, пока этот текущий максимум не изменится. У Param значение одно и оно редко меняется, поэтому оно валидируется "глобальными" максимумом и минимумом. У ParamVolatile же два значения - текущее, и текущий максимум - и они тоже валидируются через глобальные максимум и минимум, плюс текущее значение валидириуется через текущий максимум. Т.е.:


  1. и у Param, и у ParamVolatile все значения валидируются через глобальные валидаторы
  2. значение у Param и текущий максимум у ParamVolatile валидируются через глобальные валидаторы одинаково
  3. клиентский код работает со значением Param и с текущим максимумом ParamVolatile одинаково, т.к. эти значению играют одинаковую роль (если бы ParamVolatile не изменялся в текущих пределах, то всегда был бы равен текущему максимуму - т.е. аналогично просто значению из Param).
  4. текущее значение у ParamVolatile валидируется ещё и через текущий максимум


Это всё говорит о том, что при имплементации этих условий лучше бы для текущего максимума ParamVolatile унаследовать логику работы значения Param. И назвать их одинаково. А вот как конкретно - MaxValue или просто Value - другой вопрос, и больше к удобству или пониманию. Код работать будет с любым названием, если будут удовлетворяться все пункты выше.


По-моему, вы просто не можете себе представить, что за ParamVolatile такой может быть. А это просто - любое значение, которое расходуется и пополняется, и максимальная величина пополнения тоже может изменяться. И максимальная величина пополнения играет ту же роль, и так же обрабатывается многим клиентским кодом (например, он ожидает одинаковое имя свойства, а не делит их на два разных, не производит распознавание и ветвление), как и просто величина для значения, которое не расходуется и не пополняется, а просто есть. Я привёл пример скорости и запаса топлива. Скорость изменяется, но может быть и постоянной в течении какого-то времени, а топливо тратится непрерывно. Т.е. запас топлива более волатильная величина, чем скорость. Плюс топливо можно пополнить, но не более какой-то границы, а саму эту границу можно сдвинуть (у меня бак изменяемого объёма, или я канистры могу с собой взять и тасовать их - не важно).


Можно ещё сказать, что есть просто две величины - менее волатильная и более волатильная. И если менее волательную надо валидировать один раз при любом изменении, то более волатильную - дважды: текущее значение на две границы - волатильную и постоянную, и волатильную границу - на значение постоянной границы.

#69 
alex445 патриот20.05.24 16:01
NEW 20.05.24 16:01 
в ответ AlexNek 20.05.24 14:29
А вот клиентам будет путаница - все алгоритмы нужно перестроить,

то есть есть еще одно ограничение о котором умолчали?

Да, но оно простое - имена значения Param и текущего максимального значения ParamVolatile должны быть одинаковыми. Сделай это, и клиентский код будет нормально работать.

#70 
AlexNek патриот20.05.24 16:44
AlexNek
NEW 20.05.24 16:44 
в ответ alex445 20.05.24 15:59
вы просто не можете себе представить, что за ParamVolatile такой может быть

https://ru.wikipedia.org/wiki/Вола�%...

и не только это смущ

#71 
alex445 патриот20.05.24 17:28
NEW 20.05.24 17:28 
в ответ AlexNek 20.05.24 16:44

Как всегда, в английском варианте больше и подробнее, и что разные волательности бывают. Я просто выбрал название, которое считаю более подходящим.

#72 
AlexNek патриот20.05.24 19:42
AlexNek
NEW 20.05.24 19:42 
в ответ alex445 20.05.24 17:28
Я просто выбрал название, которое считаю более подходящим.

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

Когда же на это же самое смотрит кто то посторонний, то он обычно видит какую-то груду мусора.

Тоже самое было бы если бы и я какую то проблему рассказывал смущ

Но уж если сильно хочется иметь "изменчивость", это скорее variability, changeability и море других. Хотя volatility тоже как бы в этом ряду, мне он воспринимается прежде всего как финансовый термин. Особенно на русском.


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

#73 
MrSanders коренной житель20.05.24 19:47
NEW 20.05.24 19:47 
в ответ AlexNek 20.05.24 19:42

volatile в смысле "нестабильный, часто меняющийся" подобрано правильно.

#74 
AlexNek патриот20.05.24 19:55
AlexNek
NEW 20.05.24 19:55 
в ответ alex445 20.05.24 15:59
и у Param, и у ParamVolatile все значения валидируются через глобальные валидаторы

кажется, что Штирлиц начал давал показания, но нет это только видимость спок


Видимо речь о подобной функции - double ValidateParam(value, min1, max1)

хотя на самом то деле она делает что то типа этого TransformValueToRange и min1, max1 определяются в конкретном классе Param


клиентский код работает со значением Param и с текущим максимумом ParamVolatile одинаково

Это вообще абсолютно гениальное решение.

В одном случае мне выдают количество чего то, а другом максимум чего то


Есть подозрение, что с тоннами, килограммами и граммами - подобный бардак.

#75 
AlexNek патриот20.05.24 20:02
AlexNek
NEW 20.05.24 20:02 
в ответ MrSanders 20.05.24 19:47
смысле "нестабильный, часто меняющийся" подобрано правильно

дело то не только в правильности. Хотя может это и мои личные тараканы. Подобное слово у меня ассоциируется с финансами и смотреть на него просто так, со стороны совершенно непривычно, в отличии от например unstable

#76 
alex445 патриот20.05.24 20:11
NEW 20.05.24 20:11 
в ответ AlexNek 20.05.24 19:42

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

Когда же на это же самое смотрит кто то посторонний, то он обычно видит какую-то груду мусора.

Тоже самое было бы если бы и я какую то проблему рассказывал смущ

Но уж если сильно хочется иметь "изменчивость", это скорее variability, changeability и море других. Хотя volatility тоже как бы в этом ряду, мне он воспринимается прежде всего как финансовый термин. Особенно на русском.

Я хотел максимально абстрагироваться от конкретной реализации и темы. У меня в проекте эти классы с параметрами по-другому называются.


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

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

#77 
alex445 патриот20.05.24 20:20
NEW 20.05.24 20:20 
в ответ alex445 20.05.24 20:11, Последний раз изменено 20.05.24 20:25 (alex445)

За спором о названиях упустили другую важную часть - переиспользование свойств базового класса. Вам такая запись не кажется незнакомой, чужеродной, странной?


public class Parent
{
    double maxValue;
    public virtual double MaxValue
    {
        get => maxValue;
        set => maxValue = ValidateMaxValue(value);
    }
}

public class Child: Parent
{
    public override double MaxValue
    {
        get => base.MaxValue;
        set
        {
            base.MaxValue = value; // use validation from base class
            // some additional code - can be additional child class validation also, like this:
            // base.MaxValue = ValidateMaxValueInChild(value);
        }
    }
}
#78 
AlexNek патриот20.05.24 20:25
AlexNek
NEW 20.05.24 20:25 
в ответ alex445 20.05.24 20:11
Просто вы наверное не привыкли к таким областям программирования.

Скорее я не привык к подобным извращениям смущ


что делает постоянный расчёт в цикле по нескольку десятков раз в секунду
что отрабатывает раз в несколько секунд или вообще по событиям

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

#79 
alex445 патриот20.05.24 20:27
NEW 20.05.24 20:27 
в ответ AlexNek 20.05.24 20:25

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

#80 
AlexNek патриот20.05.24 20:28
AlexNek
NEW 20.05.24 20:28 
в ответ alex445 20.05.24 20:20
переиспользование свойств базового класса

обычно это функции

Закрываю глаза на всё остальное спок

#81 
alex445 патриот20.05.24 20:35
NEW 20.05.24 20:35 
в ответ AlexNek 20.05.24 20:28, Последний раз изменено 20.05.24 20:36 (alex445)
переиспользование свойств базового класса
обычно это функции
Закрываю глаза на всё остальное спок

совершенно непривычно

я не привык к подобным извращениям


Не, ну вы прямо какой-то программерский консерватор-пуританен. Неужели не хотелось иногда пошалить, нарушить табу, выйти за рамки дозволенного? Или боитесь, что Дядя Боб придёт и поставит в угол за непослушание? )))


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

#82 
AlexNek патриот20.05.24 20:36
AlexNek
NEW 20.05.24 20:36 
в ответ alex445 20.05.24 20:27
а просто код, работающий лишь с теми или другими частями параметров

Ну а на это тем более наплевать. Дай мне значение и дай мне максимум - это то что будет интересовать.

А не то что если параметр тип1 - получаем значение, а если тип2 получаем максимум.

#83 
alex445 патриот20.05.24 20:40
NEW 20.05.24 20:40 
в ответ AlexNek 20.05.24 19:55, Последний раз изменено 20.05.24 20:49 (alex445)
клиентский код работает со значением Param и с текущим максимумом ParamVolatile одинаково
Это вообще абсолютно гениальное решение.
В одном случае мне выдают количество чего то, а другом максимум чего то


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


Ну например, "бонусная карта члена клуба" - она увеличивает максимальную заправку (максимальное значение волатильного параметра) и даёт скидку (значение обычного параметра), но не увеличивает текущее значение топлива в баке (текущее значение волатильного параметра).


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

#84 
alex445 патриот20.05.24 20:44
NEW 20.05.24 20:44 
в ответ AlexNek 20.05.24 20:36
А не то что если параметр тип1 - получаем значение, а если тип2 получаем максимум.

Вот чтобы этого не было, я и назвал свойства одинаковыми именами, но значения в них хранятся по сути: для обычных параметров просто значения, для волатильных - максимальные значения. У меня в проекте они названы не MaxValue, а просто Value. Но для задания вопроса я подумал, что MaxValue наверное понятнее будет, т.к. в варианте с просто Value у волатильного параметра тогда будут свойства Value и CurrentValue, что тоже может ввести в заблуждение.

#85 
alex445 патриот20.05.24 20:52
NEW 20.05.24 20:52 
в ответ alex445 20.05.24 20:40, Последний раз изменено 20.05.24 20:52 (alex445)

Отнесение того или иного параметра к волатильному или нет (типа скорости или величины топлива в баке) зависит не от природы вещей и правдоподобных объяснений их поведений, а того, как код обрабатывает эти параметры, какие типы объектов есть в программе, влияющих на эти параметры.

#86 
AlexNek патриот20.05.24 20:53
AlexNek
NEW 20.05.24 20:53 
в ответ alex445 20.05.24 20:35
Неужели не хотелось иногда пошалить

Как то уже неинтересно класть кнопку на стул папе или маме хаха


А зачем вообще дали возможность

А какого мне могут продать хороший нож, если я с ним могу выйти на улицу и поискать развлечений?

#87 
AlexNek патриот20.05.24 20:56
AlexNek
NEW 20.05.24 20:56 
в ответ alex445 20.05.24 20:40
для обычного параметра он увеличивает просто его значение, а для волатильного - его максимальное значение

Ну так поэтому и говорю - гениальное решение бебе

#88 
AlexNek патриот20.05.24 20:58
AlexNek
NEW 20.05.24 20:58 
в ответ alex445 20.05.24 20:52
а того, как код обрабатывает эти параметры

код должен обрабатывать параметры с какой то логикой и логика не должна быть размазана по хлебу как масло.

#89 
AlexNek патриот20.05.24 21:00
AlexNek
NEW 20.05.24 21:00 
в ответ alex445 20.05.24 20:44
что тоже может ввести в заблуждение.

Похоже что какие то части кода обязательно должны вводить в заблуждение.

#90 
AlexNek патриот20.05.24 21:58
AlexNek
NEW 20.05.24 21:58 
в ответ alex445 20.05.24 20:40
Или например объект

А каким образом появились еще какие то объекты, которые связаны с несколькими различными параметрами? шок

#91 
alex445 патриот20.05.24 22:08
NEW 20.05.24 22:08 
в ответ AlexNek 20.05.24 21:58

Нада.

#92 
AlexNek патриот20.05.24 22:14
AlexNek
NEW 20.05.24 22:14 
в ответ alex445 20.05.24 22:08, Последний раз изменено 20.05.24 23:06 (AlexNek)
Нада.

Спасибо за развернутый и очень понятный ответ бебе


Мы же вроде не указываем как нужно делать, а всего лишь высказываем мнение. А мнение можно высказывать лишь на основе переданной информации.

#93 
alex445 патриот20.05.24 22:20
NEW 20.05.24 22:20 
в ответ AlexNek 20.05.24 22:14, Последний раз изменено 20.05.24 22:24 (alex445)

Так я давно передал информацию, что надо сделать. Уже много раз так и сяк сформулировал. А вы спрашиваете постоянно - а зачем, а имеет ли это какое-то отображение на реальный мир, а что скажет Дядя Боб? )))


#94 
AlexNek патриот20.05.24 22:30
AlexNek
NEW 20.05.24 22:30 
в ответ alex445 20.05.24 22:20
Так я давно передал информацию, что надо сделать

Это вам так кажется, полную модель так и не удается построить, всё время выплывает что то новое.

Сказали - хочу зеленый листик, а потихоньку выясняется для чего


#95 
AlexNek патриот20.05.24 23:12
AlexNek
NEW 20.05.24 23:12 
в ответ alex445 20.05.24 22:20
А вы спрашиваете постоянно - а зачем

Без полной "картины мира" многое кажется совершенно непонятным.

Возможно, что зная все, можно будет сказать - да других вариантов не видать.

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

#96 
alex445 патриот21.05.24 08:56
NEW 21.05.24 08:56 
в ответ AlexNek 20.05.24 23:12, Последний раз изменено 21.05.24 09:19 (alex445)

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


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


foreach(var mod in modifiers)
    foreach(var param in params) // params is a List<Param>, where Param and ParamVolatile objects are placed together
        if(mod.ParamType == param.ParamType)
            param.MaxValue += mod.Value;


Если бы param.MaxValue имело бы разное имя в классах Param и ParamVolatile (например Value и MaxValue соответственно), но одинаковое по смыслу, то мне бы пришлось усложнять код - вводить распознавание волатильного и неволатильного параметра, а присвоение значения модификатора делать всё равно одинаково, типа такого


if(param is Param) param.Value += mod.Value;
else if(param is ParamVolatile) param.MaxValue += mod.Value;


В этом нет смысла. Но это лишь одно место, где пришлось бы так усложнять. А таких мест много. Если работа с Value и MaxValue идёт одинаково, т.к. это одно значение по смыслу, то проблема не в имплементации, а лишь в названии свойства. Я могу заменить его в любой момент без изменения кода. Вы же не можете взять в голову задачу лишь из-за смущающего вас названия свойства, хотя уже 10 раз объяснено, что это такое и зачем так сделано. Я вам написал, что можно заменить название MaxValue на просто Value - это вам поможет? Вы ответили, что нет - ведь теперь непонятно, чем отличаются Value и CurrentValue в ParamVolatile. Ну придумайте вариант лучше для названия свойства, но код-то от этого не поменяется.


Ещё можно поиграться с названиями классов. Скажем, не ParamVolatile, а ParamConsumable, или ParamExpendable, или ParamReplenishable. Вам бы это больше помогло? Свойства-то так бы и остались Value и CurrentValue или MaxValue и CurrentValue.

#97 
alex445 патриот21.05.24 10:46
NEW 21.05.24 10:46 
в ответ alex445 21.05.24 08:56

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


А куда это применить и как назвать - дело десятое.


#98 
Программист коренной житель21.05.24 11:29
NEW 21.05.24 11:29 
в ответ alex445 18.05.24 07:37
Можно ли сделать лучше для описанной задачи (напомню - выделено жирным)? Может что с интерфейсами намутить?

Ничего мутить не надо.

Надо просто вынести валидацию в отдельную функцию и каждый класс должен валидировать то, за что он отвечает.


public class Param
{
    double maxValue;
    public virtual double MaxValue
    {
        get { return maxValue; }
        set
        {
           maxVaslue = value;
           Validate ();            
        }
    }

    protected virtual Validate ()
    {
    }
}
public class ParamVolatile : Param
{
    double currentValue;
    public double CurrentValue
    {
        get { return currentValue; }
        set
        {
           currentValue = value;
           Validate ();
        }
    }
    
    protected override void Validate ()
    {
        base.Validate ();
     
        currentValue = Math.Clamp(value, 0, MaxValue);
    }
}
#99 
alex445 патриот21.05.24 12:15
NEW 21.05.24 12:15 
в ответ Программист 21.05.24 11:29

Вроде неплохо, единственное что, при изменении CurrentValue вы валидируете и MaxValue, что не требуется.

alex445 патриот21.05.24 12:19
NEW 21.05.24 12:19 
в ответ alex445 21.05.24 12:15, Последний раз изменено 21.05.24 12:37 (alex445)

Хотя нет, не то. Функция валидации у меня присваивает отвалидированное значение. У вас получается, что MaxValue остаётся неприсвоенным, а присваивается лишь CurrentValue. Тут надо больше править. Что-то типа того, что ниже.


public class Param
{
    double maxValue;
    public virtual double MaxValue
    {
        get { return maxValue; }
        set
        {
           maxVaslue = value;
           Validate ();            
        }
    }
    protected void virtual Validate ()
    {
        maxValue = ... // maxValue validation
    }
}
public class ParamVolatile : Param
{
    double currentValue;
    public double CurrentValue
    {
        get { return currentValue; }
        set
        {
           currentValue = value;
           Validate ();
        }
    }
    protected override void Validate ()
    {
        base.Validate (); // maxValue validation  
        currentValue = ... // currentValue validation
    }
}


При этом зачем присвоения maxVaslue = value и currentValue = value, если мы будем их переприсваивать при валидации? А это явно из-за того, что нельзя передать параметр value в фукнцию Validate в обоих классах одинаково - т.е. сначала присвоить это значение полю, а потом поле отвалидировать внутри функции Validate. При этом функция Validate используется тоже запутанно - она ничего не возвращает, и будто поэтому ничего не меняет, а на самом деле меняет значения полей. Но мы не можем написать так, как в моём варианте maxValue = Validate(value), т.к. иначе придётся делать две фукнции валидации - для каждого свойства отдельно, каждая со своим набором параметров.


Я бы сказал, что у вас от моего варианта отилчается лишь тем, куда вы помещаете непонятную, запутанную часть кода, требующую пояснения. Вы это делаете в отдельной функции - ход её выполнение у вас нетривиальный. Зато свойства "чистые". У меня это в свойствах, а сами фукнции валидации "чистые".


Но по сути ничего не поменялось - как было у класса ParamVolatile свойство из базового класса, так и осталось, и его название будет смущать разных АлексНеков. )))

Программист коренной житель21.05.24 12:33
NEW 21.05.24 12:33 
в ответ alex445 21.05.24 12:15

MaxValue не валидируется, там пустой валидатор :)

Но если вдруг понадобится валидация MaxValue, то ее всегда можно добавить.

alex445 патриот21.05.24 12:39
NEW 21.05.24 12:39 
в ответ Программист 21.05.24 12:33, Последний раз изменено 21.05.24 12:40 (alex445)

Вобщем, ваш вариант тоже имеет право на жизнь, и от моего отличается лишь переносом неочевидной части кода в функцию валидации, и дополнительной валидацией MaxValue при изменении CurrentValue, хотя это не нужно.

Программист коренной житель21.05.24 12:45
NEW 21.05.24 12:45 
в ответ alex445 21.05.24 12:19

Прикол в том, что это нифига не вализация :)

По идее Validate должна кидать исключение :) Тут надо было бы подумать над названием функции... не знаю FitToRange или что там больше по смыслу подходит.


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

Запутанная часть кода? :) Запутанная часть кода - это херь с new :) А тут все просто.


Вы это делаете в отдельной функции - ход её выполнение у вас нетривиальный. Зато свойства "чистые". У меня это в свойствах, а сами фукнции валидации "чистые".

Ход выполнения вполне тривиальный. И, при этом, никакого дублирования кода ;)


Но по сути ничего не поменялось - как было у класса ParamVolatile свойство из базового класса, так и осталось, и его название будет смущать разных АлексНеков. )))

Ну тут уж как ты задачу сформулировал ;)

alex445 патриот21.05.24 12:56
NEW 21.05.24 12:56 
в ответ Программист 21.05.24 12:45, Последний раз изменено 21.05.24 13:09 (alex445)
Прикол в том, что это нифига не вализация :)
По идее Validate должна кидать исключение :) Тут надо было бы подумать над названием функции... не знаю FitToRange или что там больше по смыслу подходит.

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


Я бы сказал, что у вас от моего варианта отилчается лишь тем, куда вы помещаете непонятную, запутанную часть кода, требующую пояснения.
Запутанная часть кода? :) Запутанная часть кода - это херь с new :) А тут все просто.

У меня нет "хрени с new" - это был один из вариантов, который не рассматривался далее. Далее я давал ссылки на вариант с override. Вы просто перегрузили метод валидации, а я перегрузил свойство. Других особых отличий нет. Ну ещё у меня не смешаны валидация MaxValue и CurrentValue, т.к. это разные валидации. У вас же вся валидация в одном методе, метод отвечает за валидацию всего класса и вызывается при изменении любого свойства из MaxValue и CurrentValue.


Вот наши варианты (ваш я подправил, т.к. maxValue надо присвоить отвалидированное значение в любом случае). Ваш слева, мой справа.


alex445 патриот21.05.24 13:06
NEW 21.05.24 13:06 
в ответ alex445 21.05.24 12:56

У меня, например, минус в том, что переопределение всего свойства MaxValue в классе ParamVolatile явно избыточно - достаточно переписать лишь сеттер. Но сеттер отдельно не переписывается, а городить для этого отдельный метод SetMaxValue, который вызывать в сеттере же свойства MaxValue - избыточно.

alex445 патриот21.05.24 13:32
NEW 21.05.24 13:32 
в ответ Программист 21.05.24 12:45, Последний раз изменено 21.05.24 13:44 (alex445)

Вот я причесал выш код, как я бы его написал - два валидирующих метода вместо одного общего


public class Param
{
    double maxValue;
    public virtual double MaxValue
    {
        get => return maxValue;
        set => maxValue = ValidateMaxValue();
    }
 
    protected double virtual ValidateMaxValue() => ...
}


public class ParamVolatile : Param
{
    double currentValue;
    public double CurrentValue
    {
        get => return currentValue;
        set => currentValue = ValidateCurrentvValue();
    }
 
    override double ValidateMaxValue()
    {
        base.ValidateMaxValue();
        ValidateCurrentvValue();
    }
 
    double ValidateCurrentvValue() => ...
}

Вот слева направо: ваш вариант, ваш, исправленный мной, мой собственный вариант. Вот посередине - ваш исправленный - мне нравится больше всего.


alex445 патриот21.05.24 13:46
NEW 21.05.24 13:46 
в ответ alex445 21.05.24 13:32

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

Программист коренной житель21.05.24 13:51
NEW 21.05.24 13:51 
в ответ alex445 21.05.24 13:32

Я не знаю зачем надо валидировать MaxValue, ну тут уж хозяин - барин :)


Я также не совсем понимаю, каким образом тут будет установлено значение maxValue

public class Param
{
    double maxValue;
    public virtual double MaxValue
    {
        get => return maxValue;
        set => maxValue = ValidateMaxValue();
    }
 
    protected double virtual ValidateMaxValue() => ...
}

если value из сеттера не передается :)


А вот эта конструкция

    override double ValidateMaxValue()
    {
        base.ValidateMaxValue();
        ValidateCurrentvValue();
    }
 
    double ValidateCurrentvValue() => ...

необходима по одной простой причине: по какой-то неведомой причине валидации currentValue и maxValue должны иметь разные названия :)


Но спишем это все на "задачу в с тиле Murr'а", когда в процессе решения всплывает еще 100500 деталей :D


alex445 патриот21.05.24 13:57
NEW 21.05.24 13:57 
в ответ Программист 21.05.24 13:51, Последний раз изменено 21.05.24 14:51 (alex445)
Я также не совсем понимаю, каким образом тут будет установлено значение maxValue


public class Param
{
    double maxValue;
    public virtual double MaxValue
    {
        get => return maxValue;
        set => maxValue = ValidateMaxValue();
    }
 
    protected double virtual ValidateMaxValue() => ...
}
если value из сеттера не передается :)

Это я опечатался - надо передать значение из сеттера. Ещё надо присвоить currentValue при валидации MaxValue в классе ParamVolatile, затем там же вернуть отвалидированное значение MaxValue. И убрать virtual у свойства MaxValue. И изменить метод ValidateCurrentValue, чтобы он мог принимать значение MaxValue. Мдаа, много изменить надо, чтобы ваш подход применить. Вот так будет правильнее


public class Param
{
    double maxValue;
    public double MaxValue
    {
        get => return maxValue;
        set => maxValue = ValidateMaxValue(value);
    }
 
    protected virtual double ValidateMaxValue(double value) => ...
}

public class ParamVolatile : Param
{
    double currentValue;
    public double CurrentValue
    {
        get => return currentValue;
        set => currentValue = ValidateCurrentValue(value);
    }
 
    protected override double ValidateMaxValue(double maxValue)
    {
        var newMaxValue = base.ValidateMaxValue(maxValue);
        currentValue = ValidateCurrentValue(CurrentValue, newMaxValue);
        return newMaxValue;
    }
 
    double ValidateCurrentValue(double currentValue, double maxValue) => ...
}


alex445 патриот21.05.24 14:01
NEW 21.05.24 14:01 
в ответ Программист 21.05.24 13:51, Последний раз изменено 21.05.24 14:07 (alex445)
по какой-то неведомой причине валидации currentValue и maxValue должны иметь разные названия :)

Попробуйте переписать мой последний вариант с одним методом валидации. У них же разный набор параметров. И в вашем случае у вас лишняя валидация - т.е. валидируются оба свойства, когда изменяется любое из них. Заметьте, у меня идёт переприсваивание значений полей при валидации. В вашем варианте изменения всех свойств при изменении любого из них придётся клиентам класса это учитывать - что изменится MaxValue при изменении CurrentValue и наоборот. А мне нужно лишь наоборот. Поэтому валидацию этих свойств лучше разделить и вызывать отдельно или одну за другой в зависимости от того, какое свойство изменилось.

Программист коренной житель21.05.24 14:22
NEW 21.05.24 14:22 
в ответ alex445 21.05.24 14:01
У них же разный набор параметров.

Ну это уже твои тараканы :) Оба этих метода легко переписываются так, что у них вообще нет никаких параметров.


И в вашем случае у вас лишняя валидация

Нету там никакой лишней валидациию Эта функция:

    protected virtual Validate ()
    {
    }

ничего не валидирует и не изменяет. Она пустая.


Я вообще не понимаю, от куда в условии взялась необходимость валидировать/изменять maxValue (подход Murr'а? :D)


Да даже если вдруг и надо валидировать maxValue, то я не вижу в этом проблемы. Ну займет эта ненужная валидация лишких 3 такта. И что? Зато тот, кто будет использовать ParamVolatile будет уверен в том, что все поля валидны и сразу понятно где, что, как и по каким правилам меняется.

alex445 патриот21.05.24 14:28
NEW 21.05.24 14:28 
в ответ Программист 21.05.24 14:22, Последний раз изменено 21.05.24 14:30 (alex445)
Да даже если вдруг и надо валидировать maxValue, то я не вижу в этом проблемы. Ну займет эта ненужная валидация лишких 3 такта. И что? Зато тот, кто будет использовать ParamVolatile будет уверен в том, что все поля валидны и сразу понятно где, что, как и по каким правилам меняется.

Изменение CurrentValue не влияет на MaxValue. Т.е. при изменении CurrentValue не нужно лишний раз удостовериваться, что MaxValue имеет правильное значение. У вас это получается случайно, т.к. хочется всю валидацию поместить в один метод. Но при масштабировании (вовлечении в валидацию большего числа свойств) это будет давать лишнюю нагрузку и захламлять усложнять метод Validate. В моём же подходе я буду просто тасовать вызовы валидирующих методов в нужном порядке по мере увеличения свойств, требующих валидации.


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


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

Программист коренной житель21.05.24 14:48
NEW 21.05.24 14:48 
в ответ alex445 21.05.24 14:28
Т.е. при изменении CurrentValue не нужно лишний раз удостовериваться, что MaxValue имеет правильное значение.

Это очень спорное утверждение, т.к. Validate по идее должена валидировать весь объект.


У вас это получается случайно, т.к. хочется всю валидацию поместить в один метод.

Нет, никакой случайности тут нет.


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

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


А если на все это наложить требование тестируемости, то станет совсем весело :)



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

Если ничего не менялось, то и реагировать не нужно ;) Я уж не говою о том, что такого условия не было ;) Для оповещения клиентов должен быть свой механизм.


alex445 патриот21.05.24 14:52
NEW 21.05.24 14:52 
в ответ Программист 21.05.24 14:48
Т.е. при изменении CurrentValue не нужно лишний раз удостовериваться, что MaxValue имеет правильное значение.

Это очень спорное утверждение, т.к. Validate по идее должена валидировать весь объект.

Нужно ли валидировать ёмкость бака при изменении уровня топлива по мере езды или при заправке?

alex445 патриот21.05.24 14:53
NEW 21.05.24 14:53 
в ответ Программист 21.05.24 14:48, Последний раз изменено 21.05.24 14:59 (alex445)

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

Программист коренной житель21.05.24 15:10
NEW 21.05.24 15:10 
в ответ alex445 21.05.24 14:52
Нужно ли валидировать ёмкость бака при изменении уровня топлива по мере езды или при заправке?

Не нужно. Более того, емкость бака неизменяемая величина, а значит у емкости бака не должно быть никакого сеттера или другой возможности изменить этот параметр :)

alex445 патриот21.05.24 15:14
NEW 21.05.24 15:14 
в ответ Программист 21.05.24 15:10

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

alex445 патриот21.05.24 15:27
NEW 21.05.24 15:27 
в ответ alex445 21.05.24 14:53, Последний раз изменено 21.05.24 15:33 (alex445)

Переписал с одним методом валидации так. С учётом, что мне надо в методе валидации обновить отвалидированное значение изменяемого свойства, используя при этом правильные свойства, с учётом уровня доступности полей (это я про "currentValue = ... // validate currentValue using MaxValue, currentValue"). Т.е. сам метод валидации ничего не возвращает, а все присваивания полям делает внутри себя.


public class Param
{
   double maxValue;
   public double MaxValue
   {
        get => maxValue;
        set
        {
            maxValue = value;
            Validate();
        }
   }
 
   protected virtual void Validate()
   {
        maxValue = ... // validate maxValue using maxValue
   }
}

public class ParamVolatile : Param
{
   double currentValue;
   public double CurrentValue
   {
        get => currentValue;
        set
        {
            currentValue = value;
            Validate();
        }
   }

   protected override void Validate()
   {
        base.Validate();
        currentValue = ... // validate currentValue using MaxValue, currentValue
   }
}
Программист коренной житель21.05.24 15:34
NEW 21.05.24 15:34 
в ответ alex445 21.05.24 15:14
Вобщем, совсем уж от сеттера избавляться не надо, т.к. на более глобальном уровне и ёмкость бака может измениться.

Не может. Может меняться конфигурация, т.к. можно вызывать конструктор бака с одним или с другим параметром (объемом). Однако объем бака - все равно не меняется.

Программист коренной житель21.05.24 15:35
NEW 21.05.24 15:35 
в ответ alex445 21.05.24 15:27, Последний раз изменено 21.05.24 15:36 (Программист)

Найдите 10 отличий :D

#99

alex445 патриот21.05.24 15:38
NEW 21.05.24 15:38 
в ответ alex445 21.05.24 15:27, Последний раз изменено 21.05.24 16:13 (alex445)

Теперь последний штрих - справа мой вариант без перезаписанного свойства, но с отдельными методами для каждого свойства. Слева ваш - без перезаписываемого свойства, но с одним методом для всех свойств.


Думаю, тут зависит от вкуса или задачи - валидировать все свойства при любом изменении любого свойства, или валидировать лишь зависимые свойства, как в моём варианте. Если свойств много, то ваш метод Validate превращается в лапшу, а мои отдельные методы всё ещё сохранают читаемость.


Но если нужен признак валидности всего объекта, то у вас достаточно вызвать один метод, а мне - завести специальный метод на весь объект, где вызвать пачку моих отдельных методов. Или завести дополнительные поля типа bool isValidMaxValue для каждого свойства, в каждом отдельном валидирующем методе их устанавливать, а в общем валидирующем методе для всего объекта - считать их по типу bool isValidObject = isValidProp1 && isValidProp2 && isValidProp3...


alex445 патриот21.05.24 16:48
NEW 21.05.24 16:48 
в ответ Программист 21.05.24 15:34
Вобщем, совсем уж от сеттера избавляться не надо, т.к. на более глобальном уровне и ёмкость бака может измениться.

Не может. Может меняться конфигурация, т.к. можно вызывать конструктор бака с одним или с другим параметром (объемом). Однако объем бака - все равно не меняется.

А если всё таки может, то как тогда спроектировать свойство или параметр "объём бака"?


Допустим, у меня бак новой экспериментальной модели - с изменяемым объёмом. И в нём плещется топливо. И бак может изменить свой объём прямо во время движения или по мере заправки. НАДА!!

alex445 патриот21.05.24 16:53
NEW 21.05.24 16:53 
в ответ alex445 21.05.24 15:38

Кстати, нашёл ещё один минус в единственном методе Validate на весь класс. Если свойства взаимозависимы, то нужно соблюдать порядок их валидации и присвоений. Если это всё в одном методе, а свойств много, то надо перетасовывать валидации ВСЕХ свойств. А если взаимозависимые свойства сгруппированы в отдельные методы валидации, то перетасовывать надо будет только в этих методах, что куда проще. Сами же эти отдельные методы валидации могут быть применены для всего объекта в любом порядке. Но это так, планы на дальнейшее развитие.

AlexNek патриот21.05.24 18:24
AlexNek
NEW 21.05.24 18:24 
в ответ alex445 21.05.24 08:56
Вы умеете мыслить абстрактно

Похоже у нас совершенно разное определение абстрактного мышления.


То, что хочется вам, что то типа этого – а ну быстро копать яму от забора и до обеда.

Или с большой лупой ползать по земле пытаясь найти нору по следам жителя, вместо того чтобы осмотреть всё пространство с гораздо большей высоты.


Я написал, чего хочу

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

Да и хотелки то совершенно странные.


А вы не пытаетесь улучшить его

Так улучшать то особо и нечего. Когда видишь «неправильную» / непонятную архитектуру нужно разобраться вначале в ней. Уже много раз попадалось, вроде всё правильно сделано и работает, но… не в том месте.

«Это неправильные пчёлы! И они, наверное, делают неправильный мёд!»


и почему я не делаю так, как привыкли вы


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


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

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

Так смотрелось бы немного по другому

param.AddMaxValue(mod.Value)


Вы же не можете взять в голову задачу лишь из-за смущающего вас названия свойства

Нет, работа системы видится абсолютно дикой.


хотя уже 10 раз объяснено, что это такое и зачем так сделано

Эти все "объяснения" лежат на самом нижнем уровне и они не объясняют а все лишь пытаются объяснить зачем нам хочется так приспосабливаться к тому что уже есть. А вот какого так есть, так и осталось непонятным.


Вам бы это больше помогло?

Абсолютно нет, достаточно было понять что на самом деле хотелось сказать. Объект типа "А" и объект типа "Б" было даже более понятно смущ

AlexNek патриот21.05.24 18:40
AlexNek
NEW 21.05.24 18:40 
в ответ alex445 21.05.24 10:46
А куда это применить и как назвать - дело десятое.

Опять таки, с какого уровня смотреть.

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

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


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

AlexNek патриот21.05.24 19:04
AlexNek
NEW 21.05.24 19:04 
в ответ alex445 21.05.24 12:56
т.к. там может быть любая валидация, а не только приведение к диапазону

Для меня термин валидация выглядит скорее так

https://ru.wikipedia.org/wiki/Вали�%...

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

Что делать после этого - шаг номер 2

Хотя да, подобрать название для совмещенных двух шагов непросто.


alex445 патриот21.05.24 19:39
NEW 21.05.24 19:39 
в ответ AlexNek 21.05.24 18:24, Последний раз изменено 21.05.24 19:41 (alex445)
Я написал, чего хочу
В итоге то выяснилось, что хотелки и исполнение несколько другие на самом деле, чем ожидалось.
Да и хотелки то совершенно странные.

Вот два последних примера на картинке удовлетворяют мои хотелки с первой страницы.


У вас и волательность не волательность, и валидация не валидация... )))

Я уже писал - контрол, который автоматически приводит данные к заданному валидацией диапазону - валидирует эти данные или нет?

AlexNek патриот21.05.24 20:01
AlexNek
NEW 21.05.24 20:01 
в ответ alex445 21.05.24 19:39, Последний раз изменено 21.05.24 20:28 (AlexNek)
У вас и волательность не волатильность, и валидация не валидация

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


контрол, который автоматически приводит данные к заданному валидацией диапазону - валидирует эти данные или нет?

Нет конечно - он приводит данные к заданному валидацией диапазону. А то что один из шагов и есть собственно валидация данных, не даёт нам основания называть все операции вместе валидацией данных.

MrSanders коренной житель21.05.24 21:21
NEW 21.05.24 21:21 
в ответ AlexNek 21.05.24 20:01

Иманна. Валидация это проверка. Которая или возвращает true/false отвечая на вопрос"верны ли данные", или бросает исключение. Но никак не изменяет данные.

Хотим привести к "верному" состоянию, называем хотя бы "makeValid". В немецком используют глагол "plausibilisieren"

alex445 патриот21.05.24 23:16
NEW 21.05.24 23:16 
в ответ MrSanders 21.05.24 21:21, Последний раз изменено 21.05.24 23:40 (alex445)

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

)))


Кстати, насчёт "назови А или B" - там на всяких Stackoverflow всякие Джоны Скиты и Эрики Липперты жалуются, что некоторые называют классы и объекты A и B вместо скажем Animal и Tiger или foo и bar. Да кто они такие ваще против тутошних титанов?! Привыкли понимаешь там на своём гейзападе узко мыслить, а мы тут доморощенные математики абстрактные - нам подавай "треугольник а бэ цэ равен треугольнику а-штрих бэ-штрих цэ-штрих". Мене, мене, текел, упарсин.


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

Программист коренной житель22.05.24 07:48
NEW 22.05.24 07:48 
в ответ alex445 21.05.24 16:48
Допустим, у меня бак новой экспериментальной модели - с изменяемым объёмом. И в нём плещется топливо. И бак может изменить свой объём прямо во время движения или по мере заправки. НАДА!

Любые ограничения можно ввести при помощи интерфейсов.

Ты высасываешь примеры из пальца "на лету". Банальный пример, который бы тут подошел - XML де- сериализация параметров бака. В этом случае необходимы и геттер и сеттер на объекте. Решение простое - надо работать на уровне интерфейсов.

Программист коренной житель22.05.24 08:07
NEW 22.05.24 08:07 
в ответ alex445 21.05.24 16:53
Кстати, нашёл ещё один минус в единственном методе Validate на весь класс. Если свойства взаимозависимы, то нужно соблюдать порядок их валидации и присвоений. Если это всё в одном методе, а свойств много, то надо перетасовывать валидации ВСЕХ свойств. А если взаимозависимые свойства сгруппированы в отдельные методы валидации, то перетасовывать надо будет только в этих методах, что куда проще. Сами же эти отдельные методы валидации могут быть применены для всего объекта в любом порядке.

В твоей логике есть один изъян :)

Предположим у нас есть 3 своства: A, B и C. При этом A и B зависят от C.

С твои подходом нужно сделать 3 + 1 функцию: ValidateA, ValidateB, ValidateC и Validate

Выглядеть это будет так:

private void ValidateA ()
{
   ValidateC();
   a = .... 
}
private void ValidateB ()
{
   ValidateC();
   b = .... 
}
private void ValidateC ()
{
   c = .... 
}
public void Validate ()
{
   ValidateC();
   ValidateA();
   ValidateB();
}

Очевидно, что ValidateC будет вызвана аж целых 3 раза :) Можно сократить количество вызовов ValidateC до двух, но тогда будет неявная валидация С.

Можно конечно пойти еще дальше и сократить количество вызовов до 1, но тогда придется писать дополнительный код.



Ну и все это безобразие должно конкурировать с этим:

public void Validate ()
{
   // a and b depends on c. Thats'y c must be validated before!!!
   c = .... <span class="redactor-invisible-space"></span>
   a = .... <span class="redactor-invisible-space"></span>
   b = ....
}

Я не знаю что тут надо перетасовывать, но простота кода при моем подходе, как мне кажется, очевидна :)

alex445 патриот22.05.24 10:49
NEW 22.05.24 10:49 
в ответ Программист 22.05.24 07:48, Последний раз изменено 22.05.24 10:56 (alex445)
Любые ограничения можно ввести при помощи интерфейсов.
Ты высасываешь примеры из пальца "на лету". Банальный пример, который бы тут подошел - XML де- сериализация параметров бака. В этом случае необходимы и геттер и сеттер на объекте. Решение простое - надо работать на уровне интерфейсов.

Почему именно интерфейсов? Почему не включать объекты, добавляя функциональности? Типа

List<BaseProperty> Properties

где BaseProperty может быть скол угодно сложным или просто базовым классом для добавления той или иной функциональности.


Мне интерфейсы напоминают модель классов в С++ - надо иметь так называемые заголовки и реализацию, желательно в разных файлах. Лишний гемор и усложнение, если применять интерфейсы именно для цели навешивания функциональности.

alex445 патриот22.05.24 10:54
NEW 22.05.24 10:54 
в ответ Программист 22.05.24 08:07
Я не знаю что тут надо перетасовывать, но простота кода при моем подходе, как мне кажется, очевидна :)

Мне надо попробовать дальше поприменять. Может ваш подход и окажется лучшим. Пока его и оставлю - пусть будет один метод.


Хотя справедливости ради, метод-то уже не один - из-за наследования минимум он имеет перегрузку. Но в подходе с кучей методов, если добавить наследование и перегрузки, мусора и лапши будет ещё больше. У меня пока лишь два класса в иерархии наследования, поэтому пока что всё выглядит не таким уж сложным.

Программист коренной житель22.05.24 11:42
NEW 22.05.24 11:42 
в ответ alex445 22.05.24 10:49
Почему не включать объекты, добавляя функциональности?

Потому что на уровне абстракций все выглядит четче :)

Я уж не говорю о тестируемости.


List<BaseProperty> Properties
    
где BaseProperty может быть скол угодно сложным или просто базовым классом для добавления той или иной функциональности.

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

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

IEnumerable<IBaseProperty> Properties { get; }



alex445 патриот22.05.24 13:29
NEW 22.05.24 13:29 
в ответ Программист 22.05.24 11:42

Ну пусть даже этот вариант. Но чем плохо? В Unity 3D вообще именно так функциональность к объектам и цепляется.

MrSanders коренной житель22.05.24 13:58
NEW 22.05.24 13:58 
в ответ Программист 22.05.24 08:07, Последний раз изменено 22.05.24 14:06 (MrSanders)
Я не знаю что тут надо перетасовывать, но простота кода при моем подходе, как мне кажется, очевидна :)

И это всё, конечно, очень красиво. Но не жизнеспособно. Как только класс становится немножко сложнее и таскает пару десятков полей, случается ой. И дело даже не в том, что один метод валидации внезапно становится строк так 300, с этим можно бороться, а с тем, что при изменении одного параметра мы валидируем и 29 остальных. Хотя они не менялись. И понеслась. Метод начинают "оптимизировать". Типа - а если вот это так, то вот эту часть можно не проверять. И он превращается в такой клубок if-else что легче повеситься, чем разобраться.

А вот если валидировать после каждого изменения, то валидация остаётся простой. Поменялся А - я проверяю не стал ли он больше Д и не меньше 0.19 * Ф. И ускоряется.

Только вот в прошлом месяце поменяли такой "супер-валидатор" на валидацию после каждого изменения. Время исполнения одного загрузочного теста уменьшилось с 130 секунд до 28. За время выполнения теста валидация вызывалась примерно 200 тысяч раз.


ПС и теперь надо уговорить поменять валидатор для целого кластера "договор". Код вынесен в классы. Вызывается при каждом изменении (блядь!). В сумме примерно 6 тысяч строк. В гуях есть одна кнопочка, при нажатии на которую для одного договора валидация вызывается 3,5 тысяч раз. 40 секунд ждём реакции. По профайлеру из низ 39 проводим в валидаторах. Ужасные истории на ночь. (№;%:!"% привычно откликнулось эхо).

alex445 патриот22.05.24 14:30
NEW 22.05.24 14:30 
в ответ MrSanders 22.05.24 13:58, Последний раз изменено 22.05.24 14:32 (alex445)

Когда число пропертей разрастается, нужно рефакторить. Для малого числа удобнее в одном валидаторе на весь класс, для большого - как-то группировать зависимые свойства и валидировать их в группах их зависимости. Ну и общий валидатор для всего объекта тоже обычно присутствует. Главное, что нет одного универсального решения на все случаи, которое одновременно простое и для малого числа сущностей, и при сколь угодном масштабировании. В лучшем случае что можно придумать, чтобы не захламлять - использовать сторонние универсальные валидаторы, типа тех же атрибутов и фреймворков валидации для них, которые делают всю грязную работу, а ты лишь проверяешь свойства типа Property.Valid.

alex445 патриот22.05.24 14:36
NEW 22.05.24 14:36 
в ответ alex445 22.05.24 14:30, Последний раз изменено 22.05.24 14:55 (alex445)

Отвлечёмся немного на другие "рахитекурты". Ещё одно подтверждение, что многие паттерны-шматтерны это костыли для старых говноязыков и куцых фреймворков, служащие для обхода их ограничений и недостатков. Когда чел городит репозиторий, фасад и юнит оф ворк вокруг Entity Framework, хочется спросить, из какого тифозного загона он сбежал. Какой-нибудь плюсовик поди? ))) А он ведь это на автоматизме уже делает, начиная любой новый код.


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


Да вы просто неправильно его готовите, чуваки. В нашем паттерне главное отличие начинается с пятой строчки снизу, двадцатый знак слева в списке основных свойств нашего паттерна. А так он - копия другого паттерна, только сбоку. Там ниже совсем упоротые примеры по переименованию методов изкоробочного фреймворка и оборачиванию их вызовов. Уникальный шматтерн, мать его! И ведь все эти гении где-то работают, зачастую не на последних должностях. По сути всё сводится к тому, что приходя на работу куда-то ты либо соглашаешься с говнокодом местного гуру и пытаешься подражать его писулькам, либо валишь с позором из этой конторы. Искать там логику, какие-то перспективы - бесполезное занятие, зря тратящее нервы. И чем дольше в чей-то говнокод будешь погружаться, тем больше будет сужаться твоё мировоззрение и подходы.

alex445 патриот22.05.24 14:45
NEW 22.05.24 14:45 
в ответ alex445 22.05.24 14:36, Последний раз изменено 22.05.24 14:56 (alex445)

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

alex445 патриот22.05.24 15:43
NEW 22.05.24 15:43 
в ответ alex445 22.05.24 14:45, Последний раз изменено 22.05.24 15:53 (alex445)

Какие такие шматтерны? Это вообще никого не интересует. Тут начальнички всех мастей грызуться и сходят с ума, и скоро похоронят всю индустрию нафиг. Понравились фразы из комментов: "Не связано ли это с тем, что весь крупняк за последние 15 лет в той или иной степени сросся с Левиафаном и перенял у него склонность к сохранению лояльных, а не высокопрофессиональных кадров?", "ПМ просто бегает вокруг команды и следит, чтобы с лица заказчика не слезала улыбка". Только одно непонятно - на всё это кто-то должен слить прорвы денег. Кого кидают?

AlexNek патриот22.05.24 18:13
AlexNek
NEW 22.05.24 18:13 
в ответ alex445 21.05.24 23:16
а переименовать я потом могу по вкусу.

Из опыта - подобное обычно не наступает никогда. спок


Вот интересно узнать ваше мнение: сделали мне ревью кода, а я говорю - некогда фигней маяться, завтра сдавать, и так постоянно. Это правильно? Куда придём в итоге?


Главное, что код работает как мне нужно

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

AlexNek патриот22.05.24 18:16
AlexNek
NEW 22.05.24 18:16 
в ответ alex445 22.05.24 14:36
И чем дольше в чей-то говнокод будешь погружаться, тем больше будет сужаться твоё мировоззрение и подходы

вот именно, главное что бы код работал как надо бебе

alex445 патриот22.05.24 20:14
NEW 22.05.24 20:14 
в ответ AlexNek 22.05.24 18:13
а переименовать я потом могу по вкусу.

Из опыта - подобное обычно не наступает никогда.

F2, "бла-бла".

alex445 патриот22.05.24 20:16
NEW 22.05.24 20:16 
в ответ AlexNek 22.05.24 18:13, Последний раз изменено 22.05.24 20:16 (alex445)
Главное, что код работает как мне нужно
Есть только надежда, что когда то вы поймете, что главное не в работающем коде, как мне сейчас нужно.

Вы щас опять со своего острова, где все проекты на 100% вперёд проработаны и все знают изначально, чего хотят. А у меня пока непонятно, во что это выйти может - разработка экспериментальная. Может, я объединю эти свойства, а может добавлю других.

AlexNek патриот22.05.24 20:34
AlexNek
NEW 22.05.24 20:34 
в ответ alex445 22.05.24 20:16
где все проекты на 100% вперёд проработаны и все знают изначально, чего хотят

У вас несколько искаженное представление о нашем острове. смущ

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


Может, я объединю эти свойства, а может добавлю других.

опять таки, речь идет о конкретной части, а не о всей системе.

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

alex445 патриот22.05.24 20:51
NEW 22.05.24 20:51 
в ответ AlexNek 22.05.24 20:34
где все проекты на 100% вперёд проработаны и все знают изначально, чего хотят

У вас несколько искаженное представление о нашем острове. смущ

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

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


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

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

alex445 патриот22.05.24 22:35
NEW 22.05.24 22:35 
в ответ AlexNek 22.05.24 20:34

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


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

AlexNek патриот22.05.24 22:37
AlexNek
NEW 22.05.24 22:37 
в ответ alex445 22.05.24 20:51
А бывает, что надо срочно хрякнуть,

Бывает, но всё равно думаешь перед тем как делать смущ


Ну или вдруг захотелось запрещёночки?

Зачем?


Нельзя правильно подумать о том, о чём пока не имеешь полного представления.

Очень даже можно, может быть и не на 100%

Ну типа, перед тем как строить дом делаем для него фундамент. Какие будут окна и крыша фиг его знает сейчас.


типа техзадание, дизайн-документ, архитектуру, тесты

когда то было и такое


и кайфа нет

У кого как спок Кайф как раз от хорошей архитектуры.

у нас же аджайл в моде - делаем по велению левой пятки в темпе спринта

опять тема для баальшой дискуссии улыб

AlexNek патриот22.05.24 22:44
AlexNek
NEW 22.05.24 22:44 
в ответ alex445 22.05.24 22:35, Последний раз изменено 22.05.24 22:50 (AlexNek)
Я свой проект разрабатываю как прототип, и чтобы было самому интересно

ну именно так для себя и делаю постоянно.


хочу ещё что-то - архитектура не позволяет

Бывает конечно, но на любом этапе она должна быть "правильной". Что под этим понимать будет конечно у каждого по разному.

Но в любом случае это первое о чем думаешь. Код вообще не интересен.


Главное, что мне нравится,

ну так это и есть самое главное. Если делаешь для себя то всё остальное вообще полная ерунда. Хотя всё равно получается так как для других бы делал смущ

AlexNek патриот22.05.24 22:57
AlexNek
NEW 22.05.24 22:57 
в ответ alex445 22.05.24 22:35
Вы не понимаете.

Скорее всего, поэтому и хотелось знать больше. Понять другого человека очень даже не просто.

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


Когда наделаю фич

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

Программист коренной житель23.05.24 07:51
NEW 23.05.24 07:51 
в ответ MrSanders 22.05.24 13:58
За время выполнения теста валидация вызывалась примерно 200 тысяч раз.

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


В гуях есть одна кнопочка, при нажатии на которую для одного договора валидация вызывается 3,5 тысяч раз.

Ну так сами себе злобные Буратины :) Что мешает вызывать валидацию один раз? Одна кнопка - одно нажатие - одна валидация.


Многое зависит от контекста, но давай возьмем простой пример: есть некий объект с множеством зависимых друг от друга пропертей. Этот объект пересылается от А к Б в виде XML/JSON и потом восстанавливается. В общем случае, валидировать при изменении проперти (при десериализации) нельзя, т.к. мы не можем гарантировать, что сначала будут десериализованы "базовые" проперти, а потом "зависимые". Следовательно после десериализации мы должны иметь возможность валидировать весь объект.

MrSanders коренной житель23.05.24 10:45
NEW 23.05.24 10:45 
в ответ Программист 23.05.24 07:51
Я конечное многое могу понять, но зачем валидировать весь объект после каждого изменения?

А вдруг? Потому что каждая операция "независима" и не знает ничего о том кто вызывался до нее, а кто после. И она "согласованная" (consistent). Т.е. результатом каждой операции должен быть валидный объект. А значит что? Каждая операция после изменений валидирует. А пока был один большой метод, он и отрабатывал. После каждой операции.

Ну так сами себе злобные Буратины :) Что мешает вызывать валидацию один раз? Одна кнопка - одно нажатие - одна валидация.

Не-не. Кнопка-то одна, и "пользовательское действие" одно - "ausfertigen". А сам процесс, который это нажатие запускает, если расписать то 5 листов в пдф получается. И после каждой операции валидируем. Чтобы "вовремя остановиться". Ведь каждая операция у нас что? Независимая и согласованная. Прям как транзакция. И её можно использовать в куче других процессов. И это правильно, да. Но по уму валидировать надо не всё в бооольшой сети объектов. А только изменения. Добавил застрахованное здание - мне не надо валидировать 10 других зданий, только добавленное.

Этот объект пересылается от А к Б в виде XML/JSON и потом восстанавливается. В общем случае, валидировать при изменении проперти (при десериализации) нельзя, т.к. мы не можем гарантировать, что сначала будут десериализованы "базовые" проперти, а потом "зависимые".

Очень даже можно. Начиная от "подсказок" в каком порядке вызывать сеттеры десериализатору и кончая написанием своего десериализатора. Получил от JSON-а мэп и десериализируй как тебе надо. Я это, конечно, про явовские jackson и gson, но думаю в шарповских библиотеках всё достаточно похоже.


Иногда и циклическая зависимость появиться может. А зависит от Б, Б от В, а В снова от А. Тогда прячем сеттеры, в сеттерах не валидируем, а делаем подходящую по смыслу операцию, которой одновременно передаются и А, Б и В. Ну а если всё ещё сложнее (что только не придумают бвл-щики, лишь бы не думать) то говорим - сорян, сам объект ничего не гарантирует, валидация только общая (всего объекта целиком), и не вызывается при каждом изменении.


В общем я это к чему: валидацию всего объекта в одном методе (классе) я теперь делаю только тогда, когда это внешняя валидация. Не внутри самого класса. И когда валидируемый класс никаких обещаний о своей "верности" не делает (в документации).

alex445 патриот23.05.24 12:41
NEW 23.05.24 12:41 
в ответ Программист 23.05.24 07:51
За время выполнения теста валидация вызывалась примерно 200 тысяч раз.

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

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

alex445 патриот23.05.24 12:47
NEW 23.05.24 12:47 
в ответ Программист 23.05.24 07:51, Последний раз изменено 23.05.24 13:21 (alex445)
Этот объект пересылается от А к Б в виде XML/JSON и потом восстанавливается. В общем случае, валидировать при изменении проперти (при десериализации) нельзя, т.к. мы не можем гарантировать, что сначала будут десериализованы "базовые" проперти, а потом "зависимые". Следовательно после десериализации мы должны иметь возможность валидировать весь объект.

А зачем вам валидировать объект при сериализации-десериализации? Защита от изменения сериализованного объекта при его передаче? Или вы тестируете фреймворки сериализации, правильно ли и без ошибок они работают?


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


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

alex445 патриот23.05.24 12:52
NEW 23.05.24 12:52 
в ответ MrSanders 23.05.24 10:45, Последний раз изменено 23.05.24 12:52 (alex445)
Очень даже можно. Начиная от "подсказок" в каком порядке вызывать сеттеры десериализатору и кончая написанием своего десериализатора. Получил от JSON-а мэп и десериализируй как тебе надо. Я это, конечно, про явовские jackson и gson, но думаю в шарповских библиотеках всё достаточно похоже.

Конечно всё там есть. И полностью кастомная сериализация-десериализация есть.

https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Jso...

https://www.newtonsoft.com/json/help/html/JsonPropertyOrde...

alex445 патриот23.05.24 12:56
NEW 23.05.24 12:56 
в ответ MrSanders 23.05.24 10:45, Последний раз изменено 23.05.24 13:24 (alex445)
Иногда и циклическая зависимость появиться может. А зависит от Б, Б от В, а В снова от А. Тогда прячем сеттеры, в сеттерах не валидируем, а делаем подходящую по смыслу операцию, которой одновременно передаются и А, Б и В.

Некоторые сериализаторы могут сохранять ссылки на объкты - один раз сохранил объект в формате сериализации, и потом везде на его копии ссылки вставляются. Я сделал проще - у меня БД на клиенте, и она небольшая, поэтому к свойствам с объектом MyType MyObject я просто добавляю его айдишник int MyObjectId, который и сериализую (а сам объект - нет). Близко к сохранению ссылки на объект в формате сериализации.

alex445 патриот23.05.24 12:59
NEW 23.05.24 12:59 
в ответ MrSanders 23.05.24 10:45, Последний раз изменено 23.05.24 13:26 (alex445)
Ну а если всё ещё сложнее (что только не придумают бвл-щики, лишь бы не думать) то говорим - сорян, сам объект ничего не гарантирует, валидация только общая (всего объекта целиком), и не вызывается при каждом изменении.

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


Сериализовать и десериализовать айди вместо всего объекта просто. Для коллекций там сложнее. У меня есть такая конструкция. Тут бизнес логика работает лишь со свойством Items (комментарий "for business logic"), а всё остальное - обвязка. Приватные члены не сериализуются (если не обозначить атрибутом JsonProperty). Сериализуется лишь список айдишников ItemIds, который просто проходится по списку предметов, выбирая их айдишники. Для бизнес логики обвязка в виде ItemIds не используется, хотя может. Вместо ленивой инициализации можно использовать инициализацию в конструкторе. Но репозиторий тогда тоже должен быть доступен в нём же - т.е. в процессе десериализации. А это иногда нетривиально сделать. Поэтому ленивая загрузка - один из выходов.


// for deserialization and lazy initialization of Items
List<int> itemIds;

// for serialization
[JsonProperty]
List<int> ItemIds => Items.Select(i => i.Id).ToList();

// for lazy initialization of Items and as a backing field for it
List<Item> items;

// for business logic
[JsonIgnore]
public List<Item> Items => items ??= 
    itemIds
    ?.Select(/* obtain item from somewhere by its id */)
    .ToList()
    ?? new List<Item>();

[JsonConstructor]
public MyClass(List<int> itemIds)
{
    this.itemIds = itemIds;
}
1 2 3 4 5 6 7 8 все