如何修改包外的预定义包方法?

时间:2010-09-25 10:44:57

标签: java design-patterns dispatcher visitor-pattern

假设我有一个名为'animal'的包,包括动物父类,Cat延伸自Animal,Dog也来自Animal。然而,Animal的设计如下:

class Animal {
  int amount;
  Animal next; // Then a constructor initializes these.

  drinkWater(int n) { ... }
}

Cat&狗类遵循这种结构:

class Cat extends Animal {
  Cat(int amount, Animal next) {
    super(amount, next);
  }

  @Override
  drinkWater(int n) { .. }
}

他们每个人都有这样的方法,drinkWater():

public void drinkWwater(int n) {
  amount -= n;
  if (amount < 0) amount = 0;
  if (next != null) next.drinkWater(n);
}

我现在要做的是创建动物的“链表”,每个动物按顺序饮用。但是,让我们说,如果一只猫喝了一定量的水,它会将n + 1量的水传递给它。下一步

我的目的是找到一个解决方案,以克服“不接触原始动物包装,但改变每个人的饮用水行为”的问题。我带着这个'着名'天真的解决方案来上课:

class InvokeStaticTypeBDrink {
  static void typeBdrink(Animal animal, int n) {
    animal.amount -= n;
    if (animal.amount < 0) animal.amount = 0;
    if (animal.next != null) {
      if (animal instanceof Cat)
        InvokeStaticTypeDrink.drinkWater(animal.next, n+1);
      else if (animal instanceof Dog)
        InvokeStaticTypeDrink.drinkWater(animal.next, n-1);
      else
        InvokeStaticTypeDrink.drinkWater(animal.next, n);
    }
  }
}

然后,我开始研究。因为这看起来真的很快而且很脏。

所以,我发现设计模式称为“访客模式”。好吧,非常酷的模式解决了双重派遣的问题,但是我身边有一个问题:可访问的界面(声明了accept()方法)应该由原始动物“实现”。然而,我的目标是“不要对原始动物包装进行任何修改,但要改变饮用水行为”。我很确定我错过了什么。

那么,你认为一点点破解,访客模式仍然可行或其他模式/解决方案会更好吗?感谢。

2 个答案:

答案 0 :(得分:2)

如果您不想触及原始类,那么应用访问者模式的唯一方法是将原始类包装在新(包装器)类中。

无论如何,如果你只是想改变某些动物的行为,那么在你的情况下,我只会扩展那些特定类覆盖饮酒行为

然后你会有这样一只猫:

class NonThirstyCat extends Cat {
  Cat(int amount, Animal next) {
    super(amount, next);
  }

  @Override
  public void drinkWater(int n) {
    amount += n;
    if (amount < 0) amount = 0;
    if (next != null) next.drinkWater(n);
  }
}

答案 1 :(得分:0)

我认为子类化对你的情况没有帮助。

访问者模式会很好,但如果不修改Animal则无法运行。我有两个建议。实际上,我有三个:

  1. 不要这样做。重新思考你的问题。对我来说这看起来很糟糕,并且可以打破OOP的每一个原则。
  2. 使用AOP。 Google for AspectJ。
  3. 或(3)尝试这样的事情:

    class FixedAnimal extends Animal {
        public static Animal fix(Animal a) {
            Animal result = a;
            if (a instanceof Cat || a instanceof Dog)
                result = new FixedAnimal(a);
            if (a.next != null) a.next = fix(a.next);
            return result;
        }
        Animal a;
        FixedAnimal(Animal a) { 
            super(0, null); 
            this.a = a;
        }
        public void drink(int n) {
            // do stuff
            if (a.next != null) a.next.drink(n);
        }
    }
    

    当然这会对Animal的用法做出一些假设,但也许你会明白这一点。

    我的推荐是#1。或者更具体地说明你想要达到的目标。