【问题标题】:Composite Strategy pattern - java - How bad is this code?复合策略模式 - java - 这段代码有多糟糕?
【发布时间】:2010-10-31 08:18:20
【问题描述】:

这个问题是我之前帖子的延续:Visitor pattern implementation in java- How does this look?

我在重构代码时有点困惑。我正在尝试将我的访问者模式(在上一篇文章中解释)转换为复合策略模式。我正在尝试做这样的事情:

public interface Rule {
  public List<ValidatonError> check(Validatable validatable);
}

现在,我将定义这样的规则:

public class ValidCountryRule  {
  public List<ValidationError> check(Validatable validatable) {
    // invokeDAO and do something, if violation met
    // add to a list of ValidationErrors.
    // return the list.
  }
}

现在,我可以验证两种不同类型的对象。这两个可能完全不同:假设我有一个商店是Validatable,然后是一个Schedule,它是Validatable。现在,如果我要编写一个如下所示的组合:

class Validator implements Rule {
  private List<Rule> tests = new ArrayList<Rule>();

  public void addRule(Rule rule) {
    tests.add(rule);
  }

  public List<ValidationError> check(Visitable visitable) {
    List<ValidationError> list = new ArrayList<ValidationError>();
    for(Rule rule : tests) {
      list.addAll(rule.check(visitable);
    }
  }

  public Validator(ValidatorType type) {
    this.tests = type.getRules();
  }
}

我会定义一个enum,它定义了哪些检查集去哪里...

public Enum ValidatorType {
  public abstract List<Rule> getRules();
  STORE_VALIDATOR {
    public List<Rule> getRules() {
      List<Rule> rules = new ArrayList<Rule>();
      rules.add(new ValidCountryRule());
      rules.add(new ValidXYZRule());
    }

  // more validators
}

最后,我会这样使用它:

Validator validator = new Validator(ValidatorType.STORE_VALIDATOR);
for (Store store : stores) {
  validator.check(store);
}

我有一种奇怪的感觉,我的设计有缺陷。我不喜欢我的规则界面需要Validatable 的想法。您能否建议我如何改进这一点?

感谢您的帮助。

【问题讨论】:

    标签: java design-patterns oop rules strategy-pattern


    【解决方案1】:

    当我第一次了解设计模式时,我一直在努力寻找可以使用它们的地方。从那以后,我了解到过早的“模式化”有点像过早的优化。首先,尝试以直截了当的方式去做,然后看看会给你带来什么问题。

    尝试使用最少的接口和子类进行设计。然后应用任何可能适合您发现的明显冗余的模式。我从这篇文章和上一篇文章中得到的印象是你可能过度设计了你的代码。

    【讨论】:

    • @Jeremy 上面帖子中的代码示例有什么特别问题?
    • 如果你刚刚写了: for (Store store : stores) { validate_store(store);在某些时候,您将不得不定义对哪些类型执行哪些验证。硬编码比将所有这些复杂性添加到代码中然后将其外部化要糟糕得多吗?在我对代码本身进行挑剔之前,我要质疑大局。
    • @Jeremy:这听起来像是两次做同样的工作。我建议您查看ttp.essex.ac.uk 的 TTP 工具包。此外,每当我看到一种模式时,我都会使用它。我用我过去的经验来解决问题。我还参考了 UML,看看我是否可以在编码之前重构设计。这样可以节省时间,时间就是金钱。
    【解决方案2】:

    用泛型类型参数 T 替换 Validatable 以使验证框架类型安全。

    public interface Rule<T> {
        public List<ValidationError> check(T value);
    }
    

    让我们使用 ValidationStrategy 接口扩展我们的框架:

    public interface ValidationStrategy<T> {
        public List<Rule<? super T>> getRules();
    }
    

    我们正在处理以“? super T”为界的规则,因此我们可以将 Animal 的规则添加到 Dog Validator(假设 Dog 扩展 Animal)。验证器现在看起来像这样:

    public class Validator<T> implements Rule<T> {
        private List<Rule<? super T>> tests = new ArrayList<Rule<? super T>>();
    
        public Validator(ValidationStrategy<T> type) {
            this.tests = type.getRules();
        }
    
        public void addRule(Rule<? super T> rule) {
            tests.add(rule);
        }
    
        public List<ValidationError> check(T value) {
            List<ValidationError> list = new ArrayList<ValidationError>();
            for (Rule<? super T> rule : tests) {
                list.addAll(rule.check(value));
            }
            return list;
        }
    }
    

    现在我们可以像这样实现一个示例 DogValidationStrategy:

    public class DogValidationStrategy implements ValidationStrategy<Dog> {
        public List<Rule<? super Dog>> getRules() {
            List<Rule<? super Dog>> rules = new ArrayList<Rule<? super Dog>>();
            rules.add(new Rule<Dog>() {
                public List<ValidationError> check(Dog dog) {
                    // dog check...
                    return Collections.emptyList();
                }
            });
            rules.add(new Rule<Animal>() {
                public List<ValidationError> check(Animal animal) {
                    // animal check...
                    return Collections.emptyList();
                }
            });
            return rules;
        }
    }
    

    或者,就像您的示例一样,我们可能有一个 Enum 提供了几种狗验证策略:

    public enum DogValidationType implements ValidationStrategy<Dog> {
        STRATEGY_1 {
            public List<Rule<? super Dog>> getRules() {
                // answer rules...
            }
        },
        // more dog validation strategies
    }
    

    【讨论】:

    • @chris 谢谢,您的回答很有帮助。我有一个问题。在 Dog ValidationStrategy 中,我想要?不是延伸动物吗?超级狗。这将确保单个规则可以应用于 Dog 和 Cat。现在,当我尝试将所有内容声明为 T 扩展 Animal 时,编译器会抱怨 Validator 类中的 for 循环。我收到此错误消息:Rule 不适用于参数 (T)
    • @chris 你的回答最接近我想要的,如果你能回答我的评论,我会接受你的回答。
    • Jay,如果一条规则是要适用于狗猫,那不应该是一条动物规则吗?如果您可以按照您的描述进行操作,则可以在检查狗(动物)中传递一条猫规则。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 2010-10-17
    • 2010-09-25
    • 1970-01-01
    相关资源
    最近更新 更多