Добавление бифуркации в свободный интерфейсный конструктор - PullRequest
2 голосов
/ 30 декабря 2010

У меня есть небольшая структура, которая позволяет мне создавать систему трубопроводов и фильтров. У меня была идея использовать плавные интерфейсы для построения системы труб и фильтров:

        PipeFilter pipeFilter = PipeFilter.StartBuild()
            .AddFilter(new SomeFilter1())
            .AddFilter(new SomeFilter2())
            .AddFilter(new SomeFilter3())
            .AddFilter(new SomeFilter4())
            .Build();

Показанный код работает должным образом. Вот "картинка" системы:

SomeFilter1 -> SomeFilter2 -> SomeFilter3 -> SomeFilter4

Теперь существует своего рода фильтр, который вместо одного имеет два. Я называю это bifurcation. Вот пример системы с bifurcation:

              |-> SomeFilter2 -> SomeFilter3
SomeFilter1 --|
              |-> SomeFilter4

Я бы хотел реализовать что-то вроде этого:

        PipeFilter pipeFilter = PipeFilter.StartBuild()
            .AddFilter(new SomeFilter1())
            .AddBifurcation()
                .Output1()
                    .AddFilter(new SomeFilter2())
                    .AddFilter(new SomeFilter3())
                .Output2()
                    .AddFilter(new SomeFilter4())
            .Build();

Но, похоже, я просто не могу понять это правильно. Это вообще возможно, сделать? В первом примере мне просто нужен PipeFilterBuilder (который возвращается PipeFilter.StartBuild()). Во втором примере я попытался создать другие типы строителей, чтобы внести их в микс, но это, похоже, бесполезно.

Забыл упомянуть, идея заключалась в том, что я мог бы вкладывать бифуркации где угодно, то есть, я мог бы получить "деревья", полные ветвей!

Может ли кто-нибудь помочь с этим?

Ответы [ 3 ]

2 голосов
/ 30 декабря 2010

Я бы пошел следующим образом

PipeFilter pipeFilter = PipeFilter.StartBuild()
        .AddFilter(new SomeFilter1())
        .AddBifurcation(
              withOutput(1)
                 .AddFilter(new SomeFilter2())
                 .AddFilter(new SomeFilter3()), /* this separates first and second output */
              withOutput(2)
                .AddFilter(new SomeFilter4())
              )
        .Build();

В более широком формате я определяю класс Bifurcation как разработчика интерфейса Filter.

Бифуркация может иметь любойколичество выходных фильтров, связанных с использованием объекта Output.Чтобы различать эти выходные объекты, все они имеют индекс.

Как следствие, addBifurcation создает новый объект Bifurcation и добавляет его, тогда как withOutput(int) является статическим методом, создающим объект Output, который имеет всетребуемый метод.Обратите внимание, что этот пункт подразумевает, что вы избавляетесь от классического различия между Builder и построенным объектом в пользу кода, в котором методы Builder определены в базовом интерфейсе для Filter.

1 голос
/ 12 января 2011

Возможно реализовать систему так, как вы ее спроектировали.

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

Любая операция, которую вы выполняете на PipeFilterBuilder, требует обновления точки вставки и возврата самого компоновщика (this). Вызов AddBifurcation добавил бы текущую точку вставки, скажем, в стек. И наоборот, Output2 установит точку вставки в значение, извлеченное из стека. Другие функции должны быть довольно тривиальными.

1 голос
/ 30 декабря 2010

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

pipeFilter = Seq(new SomeFilter1(), 
                 Seq(new SomeFilter2(), 
                     Seq(new SomeFilter3(), new SomeFilter4())));

С таким интерфейсом совершенно очевидно, как добавить в интерфейс параллель - или вообще любой другой вид комбинатора -

pipeFilter = Seq(new SomeFilter1(), 
                Parallel(Seq(new SomeFilter2(), new SomeFilter3()),
                         Seq(new SomeFitler4())));

Хотя это может показаться громоздким, я бы предложил создать ваш интерфейс таким образом (называемый «функциональным», а не «императивным» интерфейсом), а затем написать удобные методы, чтобы уменьшить некоторые структурные нагрузки, например, варианты 1007 * и Parallel, которые принимают произвольное количество аргументов - но, вероятно, было бы лучше, если бы они просто делегировали до сгибов двоичных вариантов.

Чтобы подробнее разобраться с более тонкой конструкцией, класс или интерфейс, с которым вы работаете, - это фильтр builder , а не сам фильтр. Parallel и Seq являются методами этого класса. Это дает вам возможность реализовать комбинаторы несколькими способами для нескольких интерпретаций. Я бы написал такой интерфейс:

interface FilterBuilder<Filter> {
    Filter Seq(Filter a, Filter b);
    Filter Parallel(Filter a, Filter b);
}

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

...