如何使用两个几乎相同的 class 不共享同一个父 class?
How to use two near-identical classes that do not share the same parent class?
我有 2 个几乎相同的 class 理想情况下 应该共享同一个父 class 但不要 (因为它们来自不同的库我无法更改其源代码)。
为了举例说明,我有两个 class,例如:
public class Cat {
public void speak() {
System.out.println("Meow");
}
public CatFood findFood() {
return new CatFood();
}
public void eat(CatFood food) {
System.out.println("[Cat] Yum yum");
}
}
public class Dog {
public void speak() {
System.out.println("Woof");
}
public DogFood findFood() {
return new DogFood();
}
public void eat(DogFood food) {
System.out.println("[Dog] Yum yum");
}
}
现在理想情况下我想做这样的事情:
Animal[] animals = {new Cat(), new Dog()};
for (Animal animal : animals) {
animal.speak();
animal.eat(animal.findFood());
}
但 Cat
和 Dog
不继承自 Animal
,我无法更改它们的源代码。我也想避免依赖 instanceof
作为拐杖:
for (Object animal : animals) {
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.speak();
dog.eat(dog.findFood());
} else if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.speak();
cat.eat(cat.findFood());
} else if (animal instanceof Rabbit) { // etc etc
}
代码被复制了无数次,所以如果我对逻辑做一个小改动,我也必须复制和粘贴无数次。
那么我如何才能使用这些 classes 并尽可能减少代码重复?
如果您无法修改这些 类 并且希望将代码保持在最低限度,则可以使用反射来调用这些方法。
类似于:
Method method = obj.getClass().getMethod("speak");
method.invoke(obj);
但仅在万不得已时才考虑使用反射
您可以使用 Adapter 模式,但您需要为每种类型的动物实现一个具体的 Adapter:
interface Animal {
void speak();
void eat();
}
class DogAdapter implements Animal {
private Dog dog;
public DogAdapter(Dog dog) {
this.dog = dog;
}
public void speak() {
dog.speak();
}
public void eat() {
dog.eat(dog.findFood());
}
}
class CatAdapter implements Animal {
private Cat cat;
public CatAdapter(Cat cat) {
this.cat = cat;
}
public void speak() {
cat.speak();
}
public void eat() {
cat.eat(cat.findFood());
}
}
并且使用工厂可能会封装具体的创建:
class AnimalFactory {
public static Animal createAdapter(Dog dog) {
return new DogAdapter(dog);
}
public static Animal createAdapter(Cat cat) {
return new CatAdapter(cat);
}
}
然后你可以在一个循环中使用适配器和运行:
Animal[] animals = {AnimalFactory.createAdapter(cat), AnimalFactory.createAdapter(dog)};
for (Animal animal : animals) {
animal.speak();
animal.eat();
}
一个痛点是方法 eat()
因为 DogFood、CatFood ......也没有通用的超类型。
我有 2 个几乎相同的 class 理想情况下 应该共享同一个父 class 但不要 (因为它们来自不同的库我无法更改其源代码)。
为了举例说明,我有两个 class,例如:
public class Cat {
public void speak() {
System.out.println("Meow");
}
public CatFood findFood() {
return new CatFood();
}
public void eat(CatFood food) {
System.out.println("[Cat] Yum yum");
}
}
public class Dog {
public void speak() {
System.out.println("Woof");
}
public DogFood findFood() {
return new DogFood();
}
public void eat(DogFood food) {
System.out.println("[Dog] Yum yum");
}
}
现在理想情况下我想做这样的事情:
Animal[] animals = {new Cat(), new Dog()};
for (Animal animal : animals) {
animal.speak();
animal.eat(animal.findFood());
}
但 Cat
和 Dog
不继承自 Animal
,我无法更改它们的源代码。我也想避免依赖 instanceof
作为拐杖:
for (Object animal : animals) {
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.speak();
dog.eat(dog.findFood());
} else if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.speak();
cat.eat(cat.findFood());
} else if (animal instanceof Rabbit) { // etc etc
}
代码被复制了无数次,所以如果我对逻辑做一个小改动,我也必须复制和粘贴无数次。
那么我如何才能使用这些 classes 并尽可能减少代码重复?
如果您无法修改这些 类 并且希望将代码保持在最低限度,则可以使用反射来调用这些方法。 类似于:
Method method = obj.getClass().getMethod("speak");
method.invoke(obj);
但仅在万不得已时才考虑使用反射
您可以使用 Adapter 模式,但您需要为每种类型的动物实现一个具体的 Adapter:
interface Animal {
void speak();
void eat();
}
class DogAdapter implements Animal {
private Dog dog;
public DogAdapter(Dog dog) {
this.dog = dog;
}
public void speak() {
dog.speak();
}
public void eat() {
dog.eat(dog.findFood());
}
}
class CatAdapter implements Animal {
private Cat cat;
public CatAdapter(Cat cat) {
this.cat = cat;
}
public void speak() {
cat.speak();
}
public void eat() {
cat.eat(cat.findFood());
}
}
并且使用工厂可能会封装具体的创建:
class AnimalFactory {
public static Animal createAdapter(Dog dog) {
return new DogAdapter(dog);
}
public static Animal createAdapter(Cat cat) {
return new CatAdapter(cat);
}
}
然后你可以在一个循环中使用适配器和运行:
Animal[] animals = {AnimalFactory.createAdapter(cat), AnimalFactory.createAdapter(dog)};
for (Animal animal : animals) {
animal.speak();
animal.eat();
}
一个痛点是方法 eat()
因为 DogFood、CatFood ......也没有通用的超类型。