Будет ли это по-прежнему считаться шаблоном цепочки ответственности?

Я уже довольно давно использую шаблон проектирования и называл его "Схема цепочки ответственности ", но теперь я понимаю, что есть различия, и, возможно, это нецелесообразно. Итак, мой вопрос: 1: «Является ли следующий пример этого шаблона или его следует назвать как-то еще?» И 2: «Есть ли причина, по которой я должен предпочесть традиционный способ?».

При разработке программного обеспечения я часто использую следующий шаблон. У меня есть интерфейс, который определяет функтор, что-то вроде этого.

interface FooBar{
    boolean isFooBar( Object o );
}

Обычно это классы поиска, фильтрации или обработки; обычно что-то вроде Comparator. Метод реализации обычно функциональный (т.е. без побочных эффектов). В конце концов, я обнаружил, что создаю реализацию интерфейса, которая выглядит так:

class FooBarChain implements FooBar{
    FooBar[] foobars;

    FooBarChain( FooBar... fubars ){
         foobars = fubars;
    }

    boolean isFooBar( Object o ){
         for( FooBar f : foobars )
             if(  f.isFooBar( o )  )
                 return true;

         return false;
    }
}

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

До сих пор я обычно называл это шаблоном «Цепочка ответственности», рассматривая проблему наследования от базового класса как деталь реализации. Однако сегодня я осознал важное отличие: объекты в цепочке не могут прерывать остальную часть цепочки. Реализация не может сказать «это неверно, и я могу гарантировать, что это будет неверно для любого условия» (примечание: короткие замыкания только на true).

Итак, следует ли называть это чем-то другим, кроме схемы цепочки ответственности? Есть ли какие-либо проблемы или проблемы, которые я должен учитывать при использовании этого подхода вместо традиционного, когда экземпляры передают сообщение.


person Sled    schedule 28.06.2011    source источник


Ответы (2)


Я бы не назвал эту цепочку ответственности.

В «Цепочке ответственности» «короткое замыкание» примерно означает «Я могу справиться с этим, поэтому следующий участник в цепочке не обязан», а не является возвращаемым значением любого рода. Каждый объект в цепочке может знать, кто следующий в цепочке, и при необходимости передавать управление этому следующему объекту. Обычно они что-то делают, а не возвращают значение.

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

person Don Roby    schedule 28.06.2011
comment
Я думаю, что ключ был в том, что вы обычно делаете что-то, а не возвращаете комментарий значения. Вариант, который я использовал, - это серия текстовых фильтров. Один фильтр удаляет ругательства, еще один стоп-слова, еще один числа и т. Д. Возвращенный результат передается следующему. Если фильтр a возвращает пустую строку (например, строку, состоящую только из проклятых слов, обрабатываемых фильтром проклятий), то происходит короткое замыкание. Моя точка зрения заключалась в том, что шаблон не является логическим, я могу представить его использование с фильтрами изображений. - person Sled; 29.06.2011
comment
@ArtB: ваш пример с фильтром данных звучит как конвейер или шаблон декоратора. - person rwong; 01.01.2014

У вас есть цепочка ответственности, но вы можете создать «чистую» цепочку ответственности, добавив несколько небольших изменений.

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

 public enum Validity{
     Invalid,
     Indeterminate,
     Valid
 }

Вы можете изменить интерфейс так, чтобы он работал по цепочке:

 public interface ChainFooBar{
     public boolean isFooBar(Object o);
     public Validity checkFooBar(Object o);
 }

Большинство ваших FooBars тогда должны будут реализовать такой метод:

public abstract class AbstractFooBar implements FooBar{
    public Validity checkFooBar(Object o){
        return this.isFooBar(o) ? Validity.Valid : Validity.Indeterminate;
    }
}

Затем вы можете изменить свою цепочку, чтобы проверить любой из определенных ответов.

public class FooBarChain implements FooBar{
    private FooBar[] fooBars;

    public FooBarChain(FooBar... fooBars){
        this.fooBars = fooBars;
    }

    public Validity isFooBar(Object o){
        for(FooBar fooBar : this.fooBars){
            Validity validity = fooBar.checkFooBar(o);
            if(validity != Validity.Indeterminate){
                return validity == Validity.Valid;
            }
        }
        return false;
    }
}
person Kyle Sletten    schedule 28.06.2011
comment
Я полагаю, что мог бы, но я не думаю, что это вообще хорошая идея, я сожалею об этом. 1) он не работает с существующими интерфейсами, 2) вы действительно не хотите возвращать Inderterminate, поскольку вам нужны окончательные ответы в каждом из них. Обычно я обнаруживаю, что каждый экземпляр представляет собой определенное ограничение. Вам не нужны взаимообусловленные ответы. Кроме того, Indeterminate существует только тогда, когда вы связываете их в цепочку, когда вы имеете дело только с одним классом, который становится просто большим состоянием для обработки. Кроме того, вы не ответили, будете ли вы все еще называть это шаблоном CoR. - person Sled; 28.06.2011
comment
Я обновил свой ответ. Вопрос CoR сложен, потому что он находится где-то посередине. Когда вы добавляете возможность короткого замыкания с положительным или отрицательным ответом, вы выполняете чистый CoR, но пока он все еще CoR, но только не чистый. - person Kyle Sletten; 28.06.2011