在OOP中向现有类添加功能

时间:2015-05-19 08:43:09

标签: java c++ oop opengl

使用面向对象编程,我们经常使用多态来使几种不同类型的对象在相同的界面下运行。面包和黄油的例子是这样的:

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 :) [无论如何都要思考]。)

2 个答案:

答案 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}中}}