这个问题与所有面向对象的语言有关,但是在我的示例中,我将使用Java。
我有一个基于通用界面Renderable
的设计:
public interface Renderable {
Point getSize();
void render(Bounds bounds);
}
假设类Point
和Bounds
是POD类,以减少这些示例中的代码量:
public final class Point { public int x, y; }
public final class Bounds { public int x, y, width, height; }
该界面的目的是允许其他地方的代码首先使用getSize
计算对象的大小,确定对象在屏幕上的位置,并使用该位置和对象创建Bounds
大小,然后使用render
渲染对象。
还有一个限制,即这样的代码必须是可能的,因此不能将这些方法组合为一个:
// Ordered by dependency on size, e.g. parents come after children
Renderable[] renderables = { /* ... */ };
Map<Renderable, Point> sizes /* = ... */;
for(Renderable renderable : renderables) {
sizes.put(renderable, renderable.getSize());
}
// rearrangeObjects is an arbitrary function that may do things
// such as place children inside their parents
Map<Renderable, Bounds> bounds = rearrangeObjects(sizes);
for(Renderable renderable : renderables) {
renderable.render(bounds.get(renderable));
}
此接口的问题在于,计划实现该接口的几个类具有复杂的逻辑,这些逻辑用于根据其他位置的可变数据来计算其大小。如果不允许副作用(除了渲染对象),则每次需要渲染对象时都必须重复此逻辑。但是,如果允许有副作用,则可以在调用getSize
和render
之间缓存昂贵的计算。
此解决方案还有另一个问题:它迫使代码在getSize
之前调用render
,并且render
中使用的所有值必须 getSize
,否则它们之间的内存状态可能会改变。
有什么办法可以避免所有这些问题的实现该系统?