@Eugene-123

Реализация свойства как объекта: паттерн или антипаттерн?

Необходимо запаковать аспектные операции типа валидации, логирования, отмены/возобновления в объекте ведущим себя как свойство. Пользоваться PostSharp'oм не хочется. Внизу моя реализация(не идеальная, а так для примера) в виде класса ExtensionProperty для примитивов. Вопрос собственно в том является ли данный способ подходящим для АОП. Если ли смысл дорабатывать систему типов (такой как в коде) или лучше воспользоваться фреймворками. В реализации очень много минусов, но главный общий вопрос остается: Имеет ли смысл реализовывать свойство в виде объекта?
Код на C#
class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person();
            person.Age.Value = 100;
            person.BankAccountId.Value = 125;
            person.BankAccountId.Value = -50;
            Console.WriteLine(person);
            Console.ReadLine();
        }
    }

    // Использую данный класс для создания списка шаблонных объектов от различных типов.
    public abstract class ExtendedProperty : INotifyPropertyChanged
    {
        protected string description;

        public string Description => description;

        // Метод set доступен всем - нарушаем инкапсуляцию, но сейчас меня это не волнует.
        public abstract object Value { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    // Объект имитирующий свойство.
    // Содержит описание свойства. Производит валидацию, логирование.
    // На данный момент только для примитивов.
    public class ExtendedProperty<T> : ExtendedProperty where T : struct
    {
        private T _value;

        private readonly bool mutable;

        public Func<T, bool> Validator;
        
        public ExtendedProperty(string description, T initialValue, bool mutable = true)
        {
            this.description = description;
            this.mutable = mutable;
            _value = initialValue;
        }

        private void setValue(T value)
        {
            if (mutable)
            {
                if (Validator != null)
                {
                    if (!Validator(value))
                    {
                        Debug.WriteLine($"Wrong assignment | {description}, Value = {value}");
                        return;
                    }
                }
                if (!(_value.Equals(value)))
                {
                    Debug.WriteLine($"Modified | {description}, {_value} -> {value}");
                    _value = value;
                    OnPropertyChanged(nameof(Value));
                }
            }
            else
            {
                Debug.WriteLine($"Attempt to modify immutable value! | {Description}");
            }
        }

        private T getValue()
        {
            return _value;
        }

        public override object Value
        {
            get { return getValue(); }
            set { setValue((T)value); }
        }

        public void Undo() { /* На данный момент не реализовано. */ }

        public void Redo() { /* На данный момент не реализовано. */ }

        public override string ToString()
        {
            return $"\n[{Description} : {Value}]";
        }
    }

    public class Person
    {
        // Теперь не надо прописывать геттеры, сеттеры с логированием, OnPropertyChanged и прочей 
        // раздражающей глаза, но необходимой ересью. 
        // Теперь только лямбду для валидации, и то не во всех случаях.
        // Пока класс Person, не может узнает об изменениях (потом доработаю).
        // Объект будет представлять из себя совокупность ExtendedProperties (правда, с нарушенной инкапсуляцией). 
        // Вопрос только в том не обернется ли это адом в последующем?
        public ExtendedProperty<int> Age = new ExtendedProperty<int>("Person age", 0)
        {
            Validator = (age) => ((age >= 0) && (age <= 120))
        };

        public ExtendedProperty<int> BankAccountId = new ExtendedProperty<int>("Bank Account Id", 0)
        {
            Validator = (id) => (id >= 0)
        };

        public override string ToString()
        {
            return $"{Age}{BankAccountId}";
        }
    }
  • Вопрос задан
  • 248 просмотров
Пригласить эксперта
Ответы на вопрос 1
lxsmkv
@lxsmkv
Test automation engineer
попробуйте написать для ваших объектов юнит-тесты - если это будет легко и удобно - архитектура годная.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы