简体   繁体   English

如何使用OOP设计模式更好地实现基类属性可扩展性机制

[英]How to better implement base class property extencibility mechanism with OOP design patterns

In my project I have hierarchy of classes which implements custom properties. 在我的项目中,我具有实现自定义属性的类层次结构。 Here is more close to what I want version for the console application. 这里更接近我想要的控制台应用程序版本。

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();
    }
}

Base abstract class defines a configuration of its property objects which are intended to be inherited in derived classes. 基本抽象类定义其属性对象的配置,这些属性旨在在派生类中继承。

In the constructor configuration array is passed to MergeWithInheritedConfigsAndCreateInstances method call with second parameter set to true indicating that the instantiation of property objects have to be postponed. 在构造函数中,将数组传递给MergeWithInheritedConfigsAndCreateInstances方法调用,并将第二个参数设置为true指示必须延迟属性对象的实例化。

Current state of the merged property configuration is stored in the mergedConfigs Dictionary . 合并属性配置的当前状态存储在mergedConfigs Dictionary

Derived classes pass local property configuration to merge/override with base class configuration calling MergeWithInheritedConfigsAndCreateInstances method in its constructor with second parameter set to its default value false indicating that now property instances have to be created after merge. 派生类将本地属性配置传递给合并/覆盖,而基类配置将在其构造函数中调用MergeWithInheritedConfigsAndCreateInstances方法,并将第二个参数设置为其默认值false指示现在必须在合并后创建属性实例。

The resulting output is below. 结果输出如下。

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)

And it is what I needed, but there are some disadvantages of this solution which I do not like: 这就是我所需要的,但是我不喜欢这种解决方案的一些缺点:

1) It is necessary to call MergeWithInheritedConfigsAndCreateInstances in each constructor. 1)必须在每个构造函数中调用MergeWithInheritedConfigsAndCreateInstances Second parameter have to be provided in the abstract class constructor. 必须在抽象类构造函数中提供第二个参数。

I'd like to have a solution where all the merge/instantiate mechanism was implemented and invoked in the base class. 我想要一个在基类中实现并调用所有合并/实例化机制的解决方案。 And to be able to define derived class specific property configuration not as a method parameter but rather as member field/property (maybe of static?). 为了能够将派生类特定的属性配置定义为不是方法参数,而是成员字段/属性(也许是静态的)。

2) The merging process is done each time class is instantiated. 2)每次实例化类时,都会完成合并过程。

I'd prefer to have it done only once. 我希望只完成一次。 (placing in static constructor?) (放置在静态构造函数中?)

UPD: Rewritten example code which is better demonstrates the intended idea. UPD:重新编写的示例代码可以更好地演示预期的想法。

I think you're over-complicating things. 我认为您太过复杂了。 Even for a complicated setup, this should suffice: 即使对于复杂的设置,这也足够了:

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";
    }
}

But frankly, this is simpler and more obvious: 但坦率地说,这更加简单和明显:

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";
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM