Динамические свойства для экземпляров объектов?

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

Есть ли способ иметь динамические свойства для экземпляров класса?

Предположим, что у нас есть эта схематическая модель объекта:

объектная модель

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

диалог


person AliPST    schedule 01.02.2009    source источник


Ответы (3)


Вам нужно Properties pattern. Ознакомьтесь с длинной и скучной, но умной статьей Стива Йегге об этом< /а>

person vava    schedule 01.02.2009

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

person krosenvold    schedule 01.02.2009

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

Если вы имеете в виду поля (и объектное пространство для разреженных объектов): вы всегда можете использовать пакет свойств для реализации свойства.

Для примера С#:

string IDesigned.ApprovedBy {
    get {return GetValue<string>("ApprovedBy");}
    set {SetValue("ApprovedBy", value);}
}

со словарем для значений:

readonly Dictionary<string, object> propValues =
    new Dictionary<string, object>();
protected T GetValue<T>(string name)
{
    object val;
    if(!propValues.TryGetValue(name, out val)) return default(T);
    return (T)val;
}
protected void SetValue<T>(string name, T value)
{
    propValues[name] = value;
}

Обратите внимание, что SetValue также будет хорошим местом для любых уведомлений — например, INotifyPropertyChanged в .NET для реализации шаблона наблюдателя. Многие другие архитектуры имеют нечто подобное. Вы можете сделать то же самое с объектными ключами (например, как работает EventHandlerList), но строковые ключи проще понять ;-p

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

Последний вариант — инкапсулировать различные аспекты;

class Foo {
    public bool IsDesigned {get {return Design != null;}}
    public IDesigned Design {get;set;}
    // etc
}

Здесь Foo не реализует никаких интерфейсов, но предоставляет доступ к ним как к свойствам.

person Marc Gravell    schedule 01.02.2009
comment
Дорогой Марк. Ваш ответ очень полезен и особенно полон, я выбираю статью Стива как лучший ответ, потому что она дала мне больше деталей. Еще раз спасибо - person AliPST; 02.02.2009