在面向对象编程中,我们经常使用多态性来使几种不同类型的对象在同一个“接口(interface)”下运行。面包和黄油的例子是这样的:
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
接口(interface)(它将类转换为 OpenGL 着色器程序的原始统一值)。
到目前为止,我使用了一个简单的 instanceof
检查来处理许多可能的类型,但是我不想依赖 instanceof
因为它不容易无需修改源文件即可扩展。
UniformProvider
接口(interface)的问题在于它无法为内置类型实现,例如 float
(或 Float
)、 int
(或 Integer
)和对象数组(例如:Matrix4f[]
)。此外,我认为将统一变量转换的功能放入数学类违反了单一职责原则。
在 Rust 语言中,结构有一个有用的特性,我现在才意识到它的潜力。在传统的OOP中,类/结构实现了接口(interface)/特征,如果不修改原始文件就无法实现更多的接口(interface)。然而,在 Rust 中, 结构提供并实现了一个特征,从而扭转了依赖关系。这使用类似 impl Add for Vector4f
的语法,而不是 Vector4f implements Add
。
我正在考虑在传统的 OOP 语言(例如 Java 或 C++)中对于这种模式存在哪些选项。我考虑创建一个 converters 注册表,它们被分配给一个类:例如 FloatConverter
for float
,然后使用 HashMap 访问相关转换器或等价物,但我认为这可能效率很低。
我问有什么解决这个难题的方法(或者我是否应该改用 Rust :) [我正在考虑])。
最佳答案
一个优雅的解决方案是 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 !
关于java - 向 OOP 中的现有类添加功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30320716/