Как изменить предварительно определенные методы пакета вне пакета? - PullRequest
0 голосов
/ 25 сентября 2010

Допустим, у меня есть пакет под названием 'animal', включающий родительский класс Animal, Cat расширяется от Animal, Dog также распространяется от Animal.Animal, однако, имеет следующую конструкцию:

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

  drinkWater(int n) { ... }
}

Классы Cat & Dog имеют следующую структуру:

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 количества воды, она передает 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 ()) должен быть «реализован» оригинальными Animals.Тем не менее, моя цель - «НЕ вносить никаких изменений в оригинальную упаковку с животными, но изменять поведение питьевой воды».Я почти уверен, что что-то упустил.

Итак, как вы думаете, если немного взломать, шаблон посетителя все равно будет работать, или другой шаблон / решение будет лучше?Спасибо.

Ответы [ 2 ]

2 голосов
/ 25 сентября 2010

Если вы не хотите трогать исходные классы, то единственный способ применить шаблон посетителя - это обернуть исходные классы в новые (упаковочные) классы.

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

Тогда у тебя будет такой кот:

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);
  }
}
0 голосов
/ 25 сентября 2010

Полагаю, что подклассы не помогут в вашем случае.

Шаблон посетителя был бы хорош, но он не работает без изменения Animal. У меня есть два предложения. На самом деле у меня есть три:

  1. Не делай этого. Переосмыслите свою проблему. Для меня это выглядит как плохой дизайн и, вероятно, нарушает все принципы ООП.
  2. Используйте АОП. Google для AspectJ.

Или (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. Или более конкретно о том, чего вы хотите достичь.

...