C # Factory Pattern новичок

Я читал все, что мог найти о Factory / Abstract Factory / Simple Factory / и т. Д. Мне не удалось найти ответа на этот вопрос. Я понимаю, что классы, создаваемые фабрикой, должны реализовывать один и тот же интерфейс или производиться от одного и того же базового класса. Но что произойдет, если разные классы не получат один и тот же открытый интерфейс? I.E. SubClass1 и SubClass2 являются производными от BaseClass. Теперь SubClass1 добавляет PropertyA, а SubClass2 добавляет PropertyB. Правильно ли я предполагаю, что эти классы не могут быть созданы фабрикой, поскольку они не имеют одинаковый интерфейс? Или, если бы они были созданы как BaseClass, они бы не раскрывали свои новые свойства. Та же проблема существует с общим интерфейсом. И если кто-нибудь знает автора, который занимается этим, я был бы признателен за ссылку.

Огромное спасибо!


person TomC    schedule 31.03.2015    source источник
comment
У них все еще может быть тот же интерфейс. Если вы обращаетесь к ним через интерфейс, вы не видите дополнительных свойств.   -  person Ewan    schedule 31.03.2015
comment
согласен с Юэном. Эти классы могут быть созданы фабрикой, но без приведения вы не можете использовать расширенные свойства (методы). Вы можете использовать кастинг, но для меня это похоже на плохой подход   -  person Disappointed    schedule 31.03.2015
comment
Я тоже согласен с Эваном, также шаблоны проектирования Head First отлично подходят для объяснения нюансов шаблонов, включая Factory: amazon.co.uk/Head-First-Design-Patterns-Freeman/dp/0596007124   -  person majjam    schedule 31.03.2015
comment
Да, они могут иметь одинаковый интерфейс, но мой вопрос в том, что делать, если у них другой интерфейс. Они действительно реализуют один и тот же интерфейс, но имеют общедоступные методы, которых нет в этом интерфейсе, и поэтому эти методы не могут быть видны, если они созданы фабрикой.   -  person TomC    schedule 01.04.2015
comment
Думаю, разочарование подтвердило мои подозрения. Если я использую фабрику, мне нужно явно приводить возвращаемый объект, что как бы сводит на нет значение фабрики, помимо того, что просто небрежно. Я прочитал Head First Design Patterns (кстати, отличная книга для новичков), но, опять же, они используют лучший сценарий. Это отлично подходит для такой книги (вступление). Но я всегда ищу дыры, чтобы не попасть в них. Спасибо всем!   -  person TomC    schedule 01.04.2015


Ответы (1)


Я думаю, вы упустили назначение интерфейса. Если вы используете интерфейсы, не рекомендуется создавать классы с общедоступными методами, которые не являются частью интерфейса.

Итак, если ваша фабрика производит IAnimal. Вы не должны предполагать, что получаете класс Dog, реализующий метод WagTail, или класс Cat, который реализует LandsOnFeet. Вам нужно определить IDog и ICat. (Возможно, унаследованный от IAnimal).

Затем вы можете рассмотреть, как ведет себя ваша фабрика. У вас есть несколько вариантов.

А. Дженерики

Затем вы можете создать интерфейс Generic Factory IAnimalFactory, который при реализации возвращает либо IAnimal, либо конкретный тип.

public interface IAnimal
    {
        int Legs();
    }

public interface IAnimalFactory<T> where T: IAnimal 
{
    IAnimal CreateAnimal();
    T CreateSpecificAnimal();
}

public interface IDog:IAnimal 
{
    void WagTail();
}

public interface ICat : IAnimal
{
    void LandOnFeet();
}

public class Dog:IDog
{
//Implementation Excluded
}

public class Cat : ICat
{
 //Implementation Excluded
}

public class DogFactory:IAnimalFactory<IDog>
{
    public IAnimal CreateAnimal()
    {
        return (IAnimal)CreateSpecificAnimal();
    }

    public IDog CreateSpecificAnimal()
    {
        return new Dog();
    }

}

public class CatFactory : IAnimalFactory<ICat>
{
    public IAnimal CreateAnimal()
    {
        return (IAnimal)CreateSpecificAnimal();
    }

    public ICat CreateSpecificAnimal()
    {
        return new Cat();
    }

}

Общий подход дает вам некоторую перспективу, если вы затем решите реализовать IDomesticDog или IWildDog, и я предпочитаю, но может быть более сложным, чем необходимо, в зависимости от ваших потребностей.

Б. Конкретные методы для каждого подкласса

Вы также можете создать фабрику с функциями, которые создают собаку или кошку типа IAnimal.

public class AnimalFactory
    {
        public IAnimal GetDog()
        {
            return (IAnimal) new Dog();
        }

        public IAnimal GetCat()
        {
            return (IAnimal) new Cat();
        }

    }

Теперь, как было рекомендовано выше, вы можете безопасно выполнять трансляцию в IDog или ICat.

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

person Spevy    schedule 31.03.2015
comment
Я не согласен с вашим утверждением: «Практически каждый класс должен реализовывать интерфейс. Если классу не требуется реализовывать интерфейс, это правило приведет к появлению множества бесполезных интерфейсов. - person Bradley Uffner; 31.03.2015
comment
Справедливый комментарий @BradleyUffner Я соответствующим образом изменил. - person Spevy; 31.03.2015