模拟中“动态”对象的结构
问题描述:
我想创建一个或多或少的简单重力模拟,我目前正在对结构做出一些决定。我遇到了一个问题,我不知道如何解决“很好”。这是问题的一个简单的类图:模拟中“动态”对象的结构
在你可能无法看到任何问题,但让我告诉你一个额外的其实是一个先来看看:如果一颗恒星达到一定的密度(史瓦西半径> Radius),它应该形成一个BlackHole。那么我怎么能告诉模拟交换一个BlackHole的实例?我可以将模拟实例添加到每个主体,然后他们自己可以修改主体数组,但必须有更好的方法!
另一种方法是让Planet,Star和BlackHole成为一个新类BodyType的子类,然后Body就会保存一个实例。
您认为如何?你会如何以一种漂亮干净的方式解决这个问题?任何帮助表示赞赏!
编辑:为了进一步说明,我提到了两种方法的here is an illustration。哪一个更好?还是有没有更好的,我没有提到?
答
也许这可能有帮助;在运行时改变行为的一种常见方法是战略模式;其思想是保持Body类中所有体型的共同点,并将不同的行为分解为不同的策略,这样,只要身体改变类型,策略就可以交换。而不是让BlackHole,Planet和Star扩展Body,他们可以实现一个接口,比如BodyBehavior;
public interface BodyBehaviour {
String getType();
Double getLuminosity (Body body);
// anything else you need that's type specific....
}
public class PlanetBodyBehavior implements BodyBehaviour {
public static final String TYPE = "Planet"
@Override
public String getType() {
return TYPE;
}
@Override
public Double getLuminosity(Body body) {
// planet specific luminosity calculation - probably 0
return calculatedLuminosity;
}
}
而你的身体类会看起来像这样;
public class Body {
private Double mass;
// coordinates,radius and other state variables
private BodyBehavior bodyBehaviour;
public void setBodyBehaviour (BodyBehaviour behaviour) {
this.bodyBehaviour = behaviour;
}
public String getBodyType() {
bodyBehaviour.getType();
}
public Double getLuminosity() {
bodyBehavior.getLuminosity(this);
}
}
而对于你的模拟,你可以有一些沿线的东西;
// init - note we keep our behaviors stateless so we only need one instance of each
public class Simulation() {
BodyBehaviour planetBehavior = new PlanetBodyBehavior();
BodyBehaviour starBehavior = new StarBodyBehavior()
BodyBehaviour blackHoleBehavior = new BlackHoleBodyBehavior()
// Just showing initialisation for a single star...
Body body = new Body(initilising params....)
body.setBehaviour (starBehavior);
// iterations....
while (!finished) {
// assume we have many bodies and loop over them
for (Body body : allBodies) {
// update body positions etc.
// check it's still a star - don't want to be changing it every iteration...
if (body.hasBecomeBlackHole() {
// and this is the point of it all....
body.setBodyBehaviour(blackHoleBehavior);
}
}
}
}
快乐模拟!
注意在这种情况下,它是调用行为更改的顶级模拟循环,但可以将其添加到您的BodyBehavior;
boolean hasBecomeBlackHole (Body body);
和身体,你可以做类似
public boolean hasBecomeBlackHole() {
bodyBehaviour.hasBecomeBlackHole(this);
}
对于StarBodyBehavior;
public boolean hasBecomeBlackHole (final Body body) {
return doSomeCalculations(body.getMass(), body.getRadius());
}
而对于行星和黑洞
public boolean hasBecomeBlackHole (final Body body) {
return false;
}
非常有趣的模式,我喜欢它!但我仍然有一个问题。由于BodyBehaviour实现了类型特定的代码,因此它还需要决定何时更改为新的BodyBehaviour。所以它仍然需要对Body的引用,对吧? –
请听你喜欢它!我已经编辑过希望澄清和封装star-> bh转换的测试。您正确的是我们将自引用(this)传递给策略方法,但是它是BodyBehavior的引用的主体,而不是另一种方式。由于策略是无状态的(没有成员变量),我们只需要每种类型的一个实例,而不管模拟中有多少个实体。希望有所帮助! – GrumpyWelshGit
我想我会采用这种方法,稍作修改:而不是特定的hasBecomeBlackHole()函数,我将使用更通用的needsTransition()函数和第二个转换(Body body)函数。这样我可以实现多个可能的转换而不需要几十个函数。所以在Body类中它会检查每个更新是否需要转换,如果是,它将通过转换(Body body)传递其引用,以便BodyBehaviour可以完成必要的工作。或者第二个函数可以返回BodyBehaviour,以便Body更改它。 –