Базовый базовый класс оборачивает вложенный универсальный класс, чтобы уменьшить спецификацию аргумента типа: есть ли имя для этого шаблона?

Хорошо, название вопроса далеко не говорит само за себя. Я часто делаю это:

Из этого ответа:

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)
        {
            ....
        }
    }
}

Что я сделал: есть детали реализации KeyEqualityComparer<T, K> на что мне пришлось позвонить:

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

Вложив его как закрытый класс, я не только скрыл реализацию (открытый конструктор внутреннего класса теперь неясен), но и получил лучший синтаксис:

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

Обратите внимание, что я не наследовал вложенный класс от родительского класса (который является статическим).

Или иногда я вижу себя так:

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)
        {
            ....
        }
    }
}

Еще один похожий здесь

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
    {
        ----
    }

}

Обратите внимание, что в этих двух случаях я унаследовал от класса упаковки. Так что теперь я не только получил преимущества первого, но и смог сохранить такой список:

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

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

3 ответа

Решение

Как справедливо указал Берти, я мог бы не следовать какой-либо одной модели здесь.

Я бы сказал, что делегируя конкретизацию конкретной реализации CreateComparer метод, я только что упростил создание объекта - который находится под шаблонами метода создания. Имея статическую функцию для создания объекта, он был своего рода фабричным шаблоном - в частности, этот вариант Factory Method.

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

Также, встраивая и скрывая детали реализации (вложенные классы как таковые), открытый класс (родительский класс) подделывается к внешнему миру, как будто он выполняет свою работу. Это то, что называется паттерном делегирования

Что касается имени для сокрытия реализации универсального класса во вложенном универсальном классе, чтобы упростить сигнатуру для вызовов методов, я не думаю, что она существует. Даже если какое-либо имя существовало, оно должно быть очень специфичным для языка (или аналогичных языков), так как в нем участвуют языковые конструкции, такие как обобщение / определение типа и т. Д. Эрик Липперт находит то же самое применение во вложенных классах здесь, хотя это не связано с генериками, где он называет это фабричным шаблоном.

Я думаю, что это очень похоже на шаблон Class Clusters, который основан на шаблоне Abstract Factory.

Я не думаю, что вы следовали какой-либо одной модели здесь.

Я бы сказал, что, заменив несколько методов "CreateComparer" одним методом "Create", вы просто упростили шаблон метода создания. Вы могли бы в некотором смысле сказать, что это был своего рода Фабричный образец?! Или, может быть, модель Строителя - эта, я думаю, открыта для интерпретации?!

Встраивая "Impl" в "Equater", вы как бы следовали шаблону Command - инкапсулируя вызов метода, чтобы ваш вызывающий код не знал о том, как это делается.

В любом случае, извините, я не могу быть более полезным или дать вам определенный ответ! В любом случае, надеюсь, это поможет!

Другие вопросы по тегам