Generic base class wraps nested generic class to reduce type argument specification: Is there a name for this pattern?

青春壹個敷衍的年華 提交于 2020-01-11 07:27:06

问题


Ok question title is far from being self-explanatory. I see myself doing this often:

From this answer:

public static class Equality<T>
{
    public static IEqualityComparer<T> CreateComparer<K>(Func<T, K> keySelector)
    {
        return new KeyEqualityComparer<K>(keySelector);
    }



    class KeyEqualityComparer<K> : IEqualityComparer<T>
    {
        readonly Func<T, K> keySelector;

        public KeyEqualityComparer(Func<T, K> keySelector)
        {    
            this.keySelector = keySelector;
        }

        public bool Equals(T x, T y)
        {
            ----
        }

        public int GetHashCode(T obj)
        {
            ....
        }
    }
}

What did I do: There is an implementation detail KeyEqualityComparer<T, K> which I had to call:

new KeyEqualityComparer<Person, int>(p => p.ID);

By nesting it as a private class, not only did I hide the implementation (the public constructor of internal class is obscure now), but got a better syntax:

Equality<Person>.CreateComparer(p => p.ID);

Note here that I haven't inherited nested class from the parent class (which is static).

Or sometimes I see myself doing this:

public abstract class Equater<T> : IEqualityComparer<T>
{
    public static Equater<T> Create<TKey>(Func<T, TKey> keySelector)
    {
        return new Impl<TKey>(keySelector);
    }

    public abstract bool Equals(T x, T y);

    public abstract int GetHashCode(T obj);



    class Impl<TKey> : Equater<T>
    {
        readonly Func<T, TKey> keySelector;

        public Impl(Func<T, TKey> keySelector)
        {
            this.keySelector = keySelector;
        }

        public override bool Equals(T x, T y)
        {
            ----
        }

        public override int GetHashCode(T obj)
        {
            ....
        }
    }
}

Another similar one here

public class Accessor<S>
{
    public static Accessor<S, T> Create<T>(Expression<Func<S, T>> memberSelector)
    {
        return new GetterSetter<T>(memberSelector);
    }

    class GetterSetter<T> : Accessor<S, T>
    {
        public GetterSetter(Expression<Func<S, T>> memberSelector) : base(memberSelector)
        {

        }
    }
}

public class Accessor<S, T> : Accessor<S>
{
    Func<S, T> Getter;
    Action<S, T> Setter;

    public bool IsReadable { get; private set; }
    public bool IsWritable { get; private set; }
    public T this[S instance]
    {
        get
        {
            if (!IsReadable)
                throw new ArgumentException("Property get method not found.");

            return Getter(instance);
        }
        set
        {
            if (!IsWritable)
                throw new ArgumentException("Property set method not found.");

            Setter(instance, value);
        }
    }

    protected Accessor(Expression<Func<S, T>> memberSelector) //access not given to outside world
    {
        ----
    }

}

Note that in these two cases I inherited from wrapping class. So now not only did I get the benefits of the former but I can also maintain a list like this:

List<Equater<Person>> { persons with different implementations };

Its helping me from time to time. So I'm curious to know if there is a name for this pattern?


回答1:


I think this is a lot like Class Clusters pattern which is based on Abstract Factory pattern.




回答2:


I don't think you've followed any one pattern here.

I would say that by replacing multiple "CreateComparer" methods with a single "Create" method, you have just simplified a Creation Method pattern. You could in a sense say it was a sort of a Factory pattern?! Or maybe a Builder pattern - that one is open to interpretation I guess?!

By embedding "Impl" within "Equater" you have sort of followed the Command pattern - encapsulating method invocation so that your calling code doesn't know about how it's getting done.

Anyway, sorry I can't be more helpful than that or give you a definite answer! Anyway, hope it helps!




回答3:


As rightly pointed out by Bertie, I might have not followed any one pattern here.

I would say that by delegating the instantiation of concrete implementation to CreateComparer method, I have just simplified the object creation - which comes under Creation Method patterns. By having a static function for object instantiation, it was sort of a factory pattern - specifically this variant of Factory Method.

By inheriting Impl from Equater I have sort of followed the Abstract Factory pattern - where Equater is factory of factory and Impl is its implementation to give Impl itself back, except that Impl is really not creating any other object (in other words Impl is not meant to be a factory), but getting instantiated itself via constructor. So in strict sense, its not Abstract Factory pattern, but it will be closer to if Impl can have a method to call the constructor of itself and return back an instance.

Also by embedding and hiding the implementation detail (the nested classes as such), the exposed class (parent class) fakes to outside world as if it is doing it's job. It's what is called Delegation Pattern

As far as a name for hiding implementation of a generic class in a nested generic class to give easier signature for method calls is concerned I don't think there exist one. Even if any name existed, it has to be very specific to the language (or similar languages) since language constructs like generics/type inference etc are involved. Eric Lippert finds the same use in nested classes here although its not generics related, where he calls it Factory pattern.



来源:https://stackoverflow.com/questions/16082303/generic-base-class-wraps-nested-generic-class-to-reduce-type-argument-specificat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!