【问题标题】:How to better implement base class property extencibility mechanism with OOP design patterns如何使用 OOP 设计模式更好地实现基类属性扩展机制
【发布时间】:2016-03-31 15:15:00
【问题描述】:

在我的项目中,我有实现自定义属性的类层次结构。这里更接近我想要的控制台应用程序版本。

class Property
{
    string key;
    object value;

    public Property(string key, object value)
    {
        this.key = key;
        this.value = value;
    }

    public override string ToString()
    {
        return "(key=" + key + ": value=" + value + ")";
    }
}

public struct PropertyConfig
{
    public string key;
    public object defaultValue;
}

abstract class BaseClass
{
    Dictionary<string, Property> properties = new Dictionary<string, Property>();

    Dictionary<string, PropertyConfig> mergedConfigs = new Dictionary<string, PropertyConfig>();

    public BaseClass()
    {
        MergeWithInheritedConfigsAndCreateInstances(
            new PropertyConfig[]
            {
                new PropertyConfig() { key = "p1",  defaultValue = "v1" },
                new PropertyConfig() { key = "p2",  defaultValue = "v2" }
            }, 
            true);
    }

    protected void MergeWithInheritedConfigsAndCreateInstances(PropertyConfig[] configs = null, bool IsBaseClass = false)
    {
        configs = configs ?? new PropertyConfig[] { };

        foreach (PropertyConfig config in configs)
        {
            mergedConfigs[config.key] = config;
        }

        if (!IsBaseClass)
        {
            CreatePropertyInstancesAfterMerge();
        }
    }

    private void CreatePropertyInstancesAfterMerge()
    {
        foreach (KeyValuePair<string, PropertyConfig> kvp in mergedConfigs)
        {
            PropertyConfig config = kvp.Value;

            properties.Add(config.key, new Property(config.key, config.defaultValue));
        }
    }

    public override string ToString()
    {
        return GetType().Name + ".Properties: " + string.Join(",", properties.Select(kvp => kvp.Value.ToString()).ToArray());
    }
}

class DerivedClassA : BaseClass
{
    public DerivedClassA(): base()
    {
        MergeWithInheritedConfigsAndCreateInstances();
    }
}

class DerivedClassB : BaseClass
{
    public DerivedClassB() : base()
    {
        MergeWithInheritedConfigsAndCreateInstances(new PropertyConfig[]
        {
            new PropertyConfig() { key = "p2",  defaultValue = true },
            new PropertyConfig() { key = "p3",  defaultValue = "v3" }
        });
    }
}

class DerivedClassC : BaseClass
{
    public DerivedClassC() : base()
    {
        MergeWithInheritedConfigsAndCreateInstances(new PropertyConfig[]
        {
            new PropertyConfig() { key = "p2",  defaultValue = false },
            new PropertyConfig() { key = "p4",  defaultValue = "v4" }
        });
    }
}

class Program
{
    static void Main(string[] args)
    {
        DerivedClassA derivedA = new DerivedClassA();
        DerivedClassB derivedB = new DerivedClassB();
        DerivedClassC derivedC = new DerivedClassC();

        Console.WriteLine(derivedA.ToString());
        Console.WriteLine(derivedB.ToString());
        Console.WriteLine(derivedC.ToString());


        Console.ReadLine();
    }
}

基本抽象类定义了其属性对象的配置,这些属性对象旨在在派生类中继承。

在构造函数配置数组中传递给MergeWithInheritedConfigsAndCreateInstances方法调用,第二个参数设置为true,表示属性对象的实例化必须推迟。

合并属性配置的当前状态存储在mergedConfigs Dictionary 中。

派生类传递本地属性配置以与基类配置合并/覆盖,在其构造函数中调用MergeWithInheritedConfigsAndCreateInstances 方法,第二个参数设置为其默认值false,表示现在必须在合并后创建属性实例。

结果输出如下。

DerivedClassA.Properties: (key=p1: value=v1),(key=p2: value=v2)
DerivedClassB.Properties: (key=p1: value=v1),(key=p2: value=True),(key=p3: value=v3)
DerivedClassC.Properties: (key=p1: value=v1),(key=p2: value=False),(key=p4: value=v4)

这正是我所需要的,但这个解决方案有一些我不喜欢的缺点:

1) 必须在每个构造函数中调用MergeWithInheritedConfigsAndCreateInstances。第二个参数必须在抽象类构造函数中提供。

我想要一个解决方案,其中所有合并/实例化机制都在基类中实现和调用。并且能够定义派生类特定的属性配置,而不是作为方法参数,而是作为成员字段/属性(可能是静态的?)。

2) 每次实例化类时都会完成合并过程。

我宁愿只做一次。 (放在静态构造函数中?)

UPD:重写的示例代码更好地展示了预期的想法。

【问题讨论】:

  • 仅供参考:这就是 XAML/WPF 在具有依赖属性的底层工作方式...
  • 在我的代码中,我不能依赖 wpf 结构。尽管需求看起来相似,但 wpf 依赖属性系统的内部实现高度特定于其域,并且实现细节不能按原样重用。
  • 这不是关于重用他们的具体类,而是它背后的想法......:/

标签: c# oop design-patterns extensibility


【解决方案1】:

我认为你把事情复杂化了。即使是复杂的设置,这也足够了:

class BaseClass
{
    private readonly Dictionary<string, string> properties = new Dictionary<string, string>();
    protected string this[string key]
    {
        get { string value; return properties.TryGetValue(key, out value) ? value : null; }
        set { if (value == null) properties.Remove(key); else properties[key] = value; }
    }

    public BaseClass()
    {
        this["p1"] = "v1";
        this["p2"] = "v2";
    }

    public override string ToString()
    {
        return GetType().Name + ".Properties: " + string.Join(",", properties.Select(kvp => $"{kvp.Key}:{kvp.Value}"));
    }
}

class DerivedClass : BaseClass
{
    public DerivedClass() : base()
    {
        this["p2"] = "update";
        this["p3"] = "v3";
    }
}

但坦率地说,这更简单、更明显:

class BaseClass
{
    public string P1 {get;set;}
    public string P2 { get; set; }
    public BaseClass()
    {
        P1 = "v1";
        P2 = "v2";
    }
    public override string ToString()
    {
        return GetType().Name + ".Properties: " + string.Join(",", GetType().GetProperties(
            BindingFlags.Public | BindingFlags.Instance).Select(p => $"{p.Name}:{p.GetValue(this)}"));
    }
}

class DerivedClass : BaseClass
{
    public string P3 { get; set; }
    public DerivedClass() : base()
    {
        P2 = "update";
        P3 = "v3";
    }
}

【讨论】:

  • 谢谢!当然我过度简化了代码。任务是实现某种依赖属性系统。每个属性类都有其逻辑。基类为不同类型的属性值实现 pub/sub、getter/setter。交叉引用。可以即时添加/删除属性。有了这个问题,我需要为属性系统的一部分找到解决方案,它提供基类中定义的属性的初始化,并允许继承/覆盖/合并它们与派生类中定义的属性集。如果它过于简单化,我会重新制定它。
猜你喜欢
  • 2023-03-08
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
相关资源
最近更新 更多