如何避免在多个类中重复执行静态方法的代码

时间:2019-01-03 10:16:20

标签: c# inheritance code-duplication static-polymorphism

我有多个包含重复代码的类,尤其是成员,最重要的是一个静态方法,该方法将创建该类的新实例并返回该实例:是在字典中注册的先前创建的实例,还是通过调用构造函数注册的新实例

接口是没有选择的,因为我有静态方法。我试图通过引入实现此静态方法的基类来解决该问题,但我找不到正确创建和返回特定子类的方法。

下面是当前情况的代码示例,其中A类和B类显示重复的代码。

public class A
{
    private static readonly IDictionary<string, A> Registry = new Dictionary<string, A>();
    public string Name { get; set; }

    public A(string name)
    {
        this.Name = name;
    }

    public static A GetA(string instanceName)
    {
        lock (Registry)
        {
            if (!Registry.TryGetValue(instanceName, out var newInstance))
            {
                newInstance = new A(instanceName);
            }
            return newInstance;
        }
    }
}

然后在B类中再次有一个成员Name和GetX()方法。

public class B
{
    private static readonly IDictionary<string, B> Registry = new Dictionary<string, B>();
    public string Name { get; set; }

    public B(string name)
    {
        this.Name = name;
    }

    public static B GetB(string instanceName)
    {
        lock (Registry)
        {
            if (!Registry.TryGetValue(instanceName, out var newInstance))
            {
                newInstance = new B(instanceName);
            }
            return newInstance;
        }
    }
}

是否有可能通过引入基类或任何其他方式来避免这种代码重复?

4 个答案:

答案 0 :(得分:2)

这可能会更清洁一些

public class B: RegistryInstance<B>
{
    public string Name { get; set; }

    public B(string name)
    {
        this.Name = name;
    }
}

public class A : RegistryInstance<A>
{
    public string Name { get; set; }

    public A(string name)
    {
        this.Name = name;
    }
}

public abstract class RegistryInstance<T> where T:class
{
    protected static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();

    public static T GetInstance(string instanceName)
    {
        lock (Registry)
        {
            if (!Registry.TryGetValue(instanceName, out var newInstance))
            {
                newInstance = (T)Activator.CreateInstance(typeof(T), new object[] { instanceName });
                Registry.Add(instanceName, newInstance);
            }
            return newInstance;
        }
    }
}

答案 1 :(得分:1)

您要寻找通用的基类吗?

public abstract class BaseRegistryGetter<T>
{
    private static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
    public string Name { get; set; }

    public BaseRegistryGetter(string name)
    {
        this.Name = name;
    }

    public static T GetValue (string instanceName, Func<string, T> creator) {
        lock (Registry)
        {
            if (!Registry.TryGetValue(instanceName, out var newInstance))
            {
                newInstance = creator(instanceName);
            }
            return newInstance;
        }
    }
}

然后像这样使用它:

public class A : BaseRegistryGetter<A>
{
    public A(string name) : base(name)
    {
    }

    public static A GetA(string instanceName)
    {
        return BaseRegistryGetter<A>.GetValue(instanceName, s => new A(s));
    }
}

here中可以找到笨拙的方法来确保A的字符串构造器。

答案 2 :(得分:0)

我认为这应该有效。您可以对其进行调整以满足您的需求。另外,您的代码中存在一个错误:创建新实例时,您忘记添加到Registry中。

class Program
{
    static void Main(string[] args)
    {
        A a1 = A.GetInstance("a");
        A a2 = A.GetInstance("aa");
        A a3 = A.GetInstance("a");

        B b1 = B.GetInstance("a");
        B b2 = B.GetInstance("aa");
        B b3 = B.GetInstance("a");

        Console.WriteLine(a1 == a2); //false
        Console.WriteLine(a1 == a3); //true

        Console.WriteLine(b1 == b2); //false
        Console.WriteLine(b1 == b3); //true

        Console.ReadKey();
    }
}

public class A : Generic<A>
{
    public A(string name)
        : base(name)
    {
    }
}

public class B : Generic<B>
{
    public B(string name)
        : base(name)
    {
    }
}

public abstract class Generic<T> where T : Generic<T>
{
    private static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
    public string Name { get; set; }

    public Generic(string name)
    {
        this.Name = name;
    }

    public static T GetInstance(string instanceName)
    {
        lock (Registry)
        {
            if (!Registry.TryGetValue(instanceName, out var newInstance))
            {
                newInstance = (T)Activator.CreateInstance(typeof(T), instanceName);
                Registry.Add(instanceName, newInstance);
            }
            return newInstance;
        }
    }
}

答案 3 :(得分:0)

所有其他答案都尝试使用泛型来解决此问题,但您可能不想这样做。首先,这可能是不必要的限制,最终可能导致差异问题。其次,它只能解决一个继承级别,如果继承更多,则会再次遇到相同的问题:

 class Base<T> { ... }
 class A: Base<A> { ... }
 class B: A { //How does the generic base class help? }

有些通用解决方案没有使用泛型,因此只需要一点代码重复。一种可能是以下情况:

public class Base
{
    static readonly IDictionary<string, Base> Registry = 
        new Dictionary<string, Base>();

    protected static Base GetBase(string instanceName,
                                  Func<Base> creator)
    {
        lock (Registry)
        {
            if (!Registry.TryGetValue(instanceName, out var newInstance))
            {
                newInstance = creator();
            }   

            return newInstance;
        }
    }

    //...
}

现在,您的派生类型可以实现强类型的委托方法:

public class A: Base
{
    public A(string instanceName)
        :base(instanceName)
    {
    }
    public static A GetA(string instanceName)
        => GetBase(instanceName, () => new A(instanceName)) as A;
}

public class B: Base
{
    public B(string instanceName)
        :base(instanceName)
    {
    }
    public static B GetB(string instanceName)
        => GetBase(instanceName, () => new B(instanceName)) as B;
}