Как добавить новые производные типы в шаблон фабрики? - PullRequest
2 голосов
/ 26 июля 2011

Данный базовый тип A

И три производных типа B: AC: AD: A

У меня есть проект P. Я хочу, чтобы список представлял вхождения A в P.

Существует стратегия для извлечения Bs из P, который я хочу быть частью класса B. Есть стратегия для извлечения Cs из P, который я хочу быть частью класса C. и т.д. Я хочу, чтобы они всебыть перечисленным в одном большом Списке.

Я хочу позже иметь возможность добавить класс E: A, касаясь как можно меньше.Было бы здорово иметь виртуальный статический метод Factory на A, принимающий экземпляр P в качестве параметра, который полиморфно запускал бы все статические перегрузки в производных классах, где, например, перегрузка в C извлекала бы C из P и помещала их в List.Конечно, в C # не существует такого понятия, как виртуальный статический метод.

Я не могу сразу увидеть, как реализовать это, чтобы можно было добавлять классы D: A и E: A, не касаясьбазовый класс или какой-то постоянно обновляемый фабричный метод «Бого-метода» с конкретной зависимостью от каждого производного типа.

Здесь довольно поздно, поэтому я могу упустить что-то очевидное.Ваши мысли?

РЕДАКТИРОВАТЬ:

Мой конкретный случай заключается в том, что у меня есть система управления технологической установки, состоящая из модулей управления.Я хочу иметь возможность распознавать некоторые конструкции более высокого уровня, такие как цикл управления, настройка обратной связи и т. Д. Логика распознавания и управления этими конструкциями специфична для конкретного типа рассматриваемой конструкции.Короче говоря, я хочу связать код для идентификации и обработки конструкций.

Давайте рассмотрим аналогию.У меня есть текстовый документ.В нем есть типы слов.Слово «базовый» тип «А».Текстовый документ - это проект "P".Я могу реализовать слова типа «существительное» и «глагол».Способ, которым «существительное» идентифицируется в тексте, является специфическим для «существительного», и код должен.Список становится длиннее по мере того, как все больше и больше типов внедряются и, таким образом, идентифицируются в тексте.

Для меня имеет смысл реализовать это в существительном классе следующим образом:

 static function IEnumerable<noun> IdentifyAll (P project)

И сделать

CompleteWordList.AddRange(noun.IdentifyAll(p));

Во время инициализации, но это создает зависимостьк определенному типу "существительное" из центрального метода инициализации / фабрики.Тогда было бы трудно добавить больше классов слов, не касаясь его.Когда я пишу это, я чувствую, что склоняюсь к МЭФ.

Это простой пример.Может быть, «фраза» или что-то было бы более подходящей аналогией для базового типа, но сейчас это нужно сделать.

Даже если эти проекты представляют собой сети связанных управляющих узлов с проверяемыми свойствами (а нетекстовый документ как таковой), это очень похоже на парсер.Было бы хорошо, если бы было какое-то общее решение, которое ускользает от меня.

Ответы [ 2 ]

1 голос
/ 03 августа 2011

Хорошо, я думаю, я понял это сейчас.Если я понимаю, вы хотите взять объект типа, производного от A и определить его фактический тип (скажем, B), но без фабрики, зная, как классифицировать его как B.Тогда вы сможете ввести любое количество подтипов A в будущем, не изменяя фабрику для каждого нового типа.

Кто-то знает, как получить из Aдо B.Если это не фабрика, то это должен быть B сам по себе.Я вижу, что вы пошли по этому пути и подумали: «Мне нужен метод виртуальной фабрики, чтобы каждый подтип A мог предоставить спецификацию для идентификации себя».

Как вы сказали, виртуальных статических методов не существуеттак что вы не можете делать это так, как думали.Но почему бы не использовать метод экземпляра?

Пока проект содержит список всех известных подтипов, он может просто перебирать эти типы, создавая их экземпляры и спрашивая их "Является ли этот объект одним из вас?"».И если он говорит «да», вы можете попросить его «дать мне ваш экземпляр, эквивалентный этому экземпляру базового типа».(Это звучит неэффективно; на практике, конечно, вы могли бы просто сохранить один «фабричный экземпляр» каждого типа живым, чтобы вам не приходилось их воссоздавать).

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;

interface IWord
{
    bool IsTypeOf(IWord word);
    string Text { get; set; }
    IWord MakeFrom(IWord word);
}

// the base type
class UntypedWord : IWord
{
    public virtual string Text { get; set; }
    public virtual bool IsTypeOf(IWord word)
    {
        throw new NotImplementedException();
    }
    public virtual IWord MakeFrom(IWord word)
    {
        throw new NotImplementedException();
    }
}

// one specific subtype
class ColorWord : UntypedWord
{
    public Color Color { get; private set; }

    public override bool IsTypeOf(IWord word)
    {
        return word.Text == "red" || word.Text == "green" || word.Text == "blue";
    }

    public override IWord MakeFrom(IWord word)
    {
        var newMe = new ColorWord();
        newMe.Text = word.Text;
        if (word.Text == "red") newMe.Color = Color.Red;
        else if (word.Text == "blue") newMe.Color = Color.Blue;
        else if (word.Text == "yellow") newMe.Color = Color.Yellow;
        return newMe;            
    }
}

// another specific type
class NumberWord : IWord // note: not an UntypedWord (see comments below)
{
    public int Number { get; set; }
    public string Text { get; set; }

    public bool IsTypeOf(IWord word)
    {
        return word.Text == "one" || word.Text == "two" || word.Text == "three";
    }

    public IWord MakeFrom(IWord word)
    {
        var newMe = new NumberWord();
        newMe.Text = word.Text;
        if (word.Text == "one") newMe.Number = 1;
        else if (word.Text == "two") newMe.Number = 2;
        else if (word.Text == "three") newMe.Number = 3;
        return newMe;
    }
}


class WordList
{
    Collection<Type> WordTypes = new Collection<Type>();
    Collection<IWord> UntypedWords = new Collection<IWord>();
    Dictionary<Type, Collection<IWord>> StronglyTypedWords = new Dictionary<Type, Collection<IWord>>();

    public void AddWordType<T>() where T : IWord
    {
        WordTypes.Add(typeof(T));

        if (!StronglyTypedWords.ContainsKey(typeof(T)))
            StronglyTypedWords[typeof(T)] = new Collection<IWord>();
    }

    public void Add(IWord word)
    {
        bool foundType = false;
        foreach (Type type in WordTypes)
        {
            // in practice you'd cache these factories for efficiency
            IWord instance = Activator.CreateInstance(type) as IWord;
            if (instance.IsTypeOf(word))
            {
                if (!StronglyTypedWords.ContainsKey(type))
                    StronglyTypedWords[type] = new Collection<IWord>();

                StronglyTypedWords[type].Add(instance.MakeFrom(word));
                foundType = true;
            }
        }
        if (!foundType)
            UntypedWords.Add(word);
    }

    public int HowManyWordsOfType<T>()
    {
        if (StronglyTypedWords.ContainsKey(typeof(T)))
            return StronglyTypedWords[typeof(T)].Count;
        return 0;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var sentence = new WordList();
        sentence.AddWordType<ColorWord>();
        sentence.AddWordType<NumberWord>();

        sentence.Add(new UntypedWord { Text = "two" });
        sentence.Add(new UntypedWord { Text = "green" });
        sentence.Add(new UntypedWord { Text = "frogs" });
        sentence.Add(new UntypedWord { Text = "and" });
        sentence.Add(new UntypedWord { Text = "one" });
        sentence.Add(new UntypedWord { Text = "red" });
        sentence.Add(new UntypedWord { Text = "rose" });

        Console.WriteLine("color words: " + sentence.HowManyWordsOfType<ColorWord>());
        Console.WriteLine("number words: " + sentence.HowManyWordsOfType<NumberWord>());
    }
}    

Вывод:

color words: 2
number words: 2

Теперь, когда вы хотите добавить новый тип слова, вам нужно добавить только следующий код:

sentence.AddWordType<NewWordType>();

ВыВы заметите, что ColorWord является подтипом UntypedWord, а NumberWord - нет.Типы слов не должны иметь общий базовый тип, если они реализуют IWord.

Очевидно, что это нелепый пример, но он показывает, как каждый подтип владеет логикой для классификации на основе свойств данного объекта.общего супертипа (или общего интерфейса), и он знает, как создать свой экземпляр на основе данного объекта.

Так что теперь класс WordList (ваш P) никогда не должен обновлятьсядля размещения новых типов слов.Вам просто нужно рассказать обо всех типах во время выполнения.

И вы можете написать свой IdentifyAll(WordList sentence) метод, только это будет метод экземпляра вместо статического.

0 голосов
/ 26 июля 2011

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

По сути, ваша фабрика становится системой корреляции, которая принимает описание корреляции между условием, которое должно быть выполнено, и типом, который необходимо создать;затем все, что делает фабрика, это считывает конфигурацию (или использует ее введенную конфигурацию) и выполняет любую логику, определенную, чтобы определить, какой код создания использовать.Это Фабрика как объект, управляемый данными.Весна делает что-то очень похожее на это;Конфигурация Spring определяет взаимосвязи между объектами и типами, которые подходят для внедрения, и Spring просто делает то, что ему говорят.Этот тип системы сложен, но ОЧЕНЬ расширяем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...