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

发布于 2024-09-25 01:34:08 字数 1475 浏览 5 评论 0原文

假设我有一个名为“animal”的包,其中包括 Animal 父类,Cat 继承自 Animal,Dog 也继承自 Animal。然而,《动物》的设计是这样的:

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

  drinkWater(int n) { ... }
}

《猫与动物》。狗类遵循以下结构:

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);
    }
  }
}

然后,我开始研究。因为这确实看起来又快又脏的解决方案。

所以,我发现了一种称为“访客模式”的设计模式。嗯,非常酷的模式解决了双重调度的问题,但我这边有一个问题:Visible 接口(声明accept() 方法)应该由原始的 Animals '实现'。然而,我的目标是“不要对原始动物包装进行任何修改,但要改变饮用水行为”。我很确定我错过了一些东西。

那么,您认为通过一点点修改,访问者模式仍然可以工作,还是其他模式/解决方案会更好?谢谢。

Let's say I have a package called 'animal' including Animal parent class, Cat extends from Animal, Dog extends from Animal, also. Animal, however, is designed like this:

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

  drinkWater(int n) { ... }
}

Cat & Dog classes follow this structure:

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

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

Each of them has the method, drinkWater() like this:

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

What I am trying to do now here is I created a 'linked list' of animals, each of them drinking water in sequence. However, let's say, if a cat drinks n amount of water, it passes n+1 amount of water to its.next

My purpose is finding a solution to overcome the problem that 'don't touch the original animal package, but change behavior of drinking water each one of them'. I have come with that 'famous' naive solution with a class:

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);
    }
  }
}

Then, I started to research. Because this really looked quick and dirty solution.

So, I found that design pattern called 'Visitor Pattern'. Well, pretty cool pattern which solves the problem with double dispatch, but there is a problem on my side: Visitable interface (which declares accept() method) should be 'implement'ed by the original Animals. However, my goal is 'do NOT to do any modification on original animal package, but do change the drinking water behavior'. I am pretty sure I am missing something.

So, do you think with a little bit hack, Visitor Pattern would still work or another pattern/solution would be better? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

倾城花音 2024-10-02 01:34:08

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

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

那么你就会有一只这样的猫:

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);
  }
}

If you do not want to touch the original classes, then the only way to apply visitor pattern would be to wrap the original classes inside new (wrapper) classes.

Anyway, if you just want to change the behavior of some animals, then in your situation I would just extend those specific classes and override the drinking behavior.

Then you would have a cat like this:

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);
  }
}
北音执念 2024-10-02 01:34:08

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

访问者模式很好,但如果不修改 Animal,它就无法工作。我有两个建议。事实上,我有三个建议:

  1. 不要这样做。重新思考你的问题。在我看来,它的设计很糟糕,而且很可能违反了 OOP 的每一条原则。
  2. 使用AOP。谷歌搜索 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。或者更具体地说明您想要实现的目标。

I suppose subclassing will not help in your case.

The visitor pattern would be good but it does not work without modifying Animal. I have two suggestions. Actually, I have three:

  1. Don't do it. Rethink your problem. It looks like bad design to me and propably breaks every principle of OOP.
  2. Use AOP. Google for AspectJ.

Or (3) try something like this:

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);
    }
}

Of course this makes some assumptions about the usage of Animal, but maybe you get the idea.

My recommendation would be #1. Or be more specific about what you want to achieve.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文