使用面向对象编程,我们经常使用多态来使几种不同类型的对象在相同的界面下运行。面包和黄油的例子是这样的:
public abstract class Animal {
public abstract void makeSound();
}
public class Dog extends Animal {
public void makeSound() {
System.out.println("Woof woof");
}
}
public class Cat extends Animal {
public void makeSound() {
System.out.println("Meow");
}
}
我们不关心真正的动物是什么,只关心它能发出声音。
但是,当我们想要向现有类添加新功能时,会出现问题。
在我的例子中,我试图让几个类实现UniformProvider
接口(它将类转换为OpenGL着色器程序的原始统一值)。
到目前为止,我使用了一个简单的instanceof
检查来处理多种可能的类型,但是我不想依赖instanceof
,因为如果不修改它就不容易扩展源文件。
UniformProvider
界面的问题在于,无法为float
(或Float
),int
(或Integer
等内置类型实施此问题)和对象数组(例如:Matrix4f[]
)。此外,我认为将统一变量转换的功能放入数学类会违反单一责任原则。
在Rust语言中,结构体有一个有用的功能,我现在才意识到它的潜力。在传统的OOP中,类/结构实现了接口/特性,并且可以在不修改原始文件的情况下实现更多接口。但是在Rust中,为一个结构提供了一个特征的实现,从而扭转了依赖关系。这使用impl Add for Vector4f
之类的语法而不是Vector4f implements Add
。
我正在思考传统的OOP语言中存在哪些选项,例如Java或C ++这样的模式。我考虑创建一个 converter 的注册表,它们分配给一个类:例如FloatConverter
用于float
,然后使用HashMap或等价物访问相关的转换器,但我想这可能效率很低。
我问这个困境的解决方案是什么(或者我应该切换到Rust :) [无论如何都要思考]。)
答案 0 :(得分:0)
优雅的解决方案是Visitor Pattern
// Base object hierarchy
abstract class Animal {
abstract void Accept(AnimalVisitor visitor);
}
class Dog extends Animal {
void Accept(AnimalVisitor visitor) { visitor.Visit(this); }
}
class Cat extends Animal {
void Accept(AnimalVisitor visitor) { visitor.Visit(this); }
}
interface AnimalVisitor {
Visit(Dog dog);
Visit(Cat cat);
}
// Here is a concrete visitor ...
class AnimalNoiseMaker implements AnimalVisitor {
Visit(Dog dog) { System.out.println("Woof woof"); }
Visit(Cat cat) { System.out.println("Meow"); }
}
// .. and how you use it
Animal a = ...;
a.Accept(new AnimalNoiseMaker()); // Woof or Meow !
答案 1 :(得分:0)
当我无法修改现有类时,我经常使用decorator pattern向现有类添加行为:
public final class EmpoweredAnimal extends Animal
{
private final Animal animal;
public EmpoweredAnimal(Animal animal)
{
this.animal = animal;
}
@Override
public final void makeSound()
{
this.animal.makeSound();
}
public final void jump()
{
// TODO
}
}
用法:
Animal myDog = new Dog();
//Drawback: you must base your polymorphism on the EmpoweredAnimal now
EmpoweredAnimal myEmpoweredDog = new EmpoweredAnimal(myDog);
myEmpoweredDog.makeSound(); //prints "woof woof"
myEmpoweredDog.jump(); //do something new
如果你的所有动物都必须被赋予权力,那么这个缺点是可以接受的,否则你不得不继续使用 instanceof ,因为并非Animal
都被包裹在{{1}中}}