上下文:我认为Java中的对象创建和管理在编程时应该考虑到成本。但是,我不知道这个成本有多大。因此我的问题是:
我有多个共享相同参数的函数:
detectCollision(ArrayList<Mobile>, ArrayList<Inert>, double dt)
updatePositions(ArrayList<Mobile>, double dt)
我认为,有两种方法可以组织它们(见下面的代码):
请注意,Mover
对象没有私有内部状态,只是一堆使用参数ArrayList<Mobile>
,ArrayList<Inert>
,double dt
的算法。
问题:首选哪种方法?它有成本吗?是否有更标准的替代方案?
这是一个说明第一点的片段:
public class Mover{
public static void updatePositions(ArrayList<Mobile>, double dt){...}
/* remove the static keyword if you need polymorphism, it doesn't change the question */
public static Collisions detectCollision(ArrayList<Mobile>, ArrayList<Inert>, double dt){...}
//etc.
}
这是一个说明第二点的片段:
public class Mover{
public Mover(ArrayList<Mobile>, ArrayList<Inert>, double dt){...}
public void updatePositions(){...}
public Collisions detectCollision(){...}
//etc.
private ArrayList<Mobile> mobiles;
private ArrayList<Inert> inerts;
//etc.
}
答案 0 :(得分:2)
我建议你选择第二个版本。除了良好的可读性之外,它还允许您稍后扩展课程(请参阅SOLID - &gt;打开/关闭原则)。一般来说,我永远不会创建这样的实用程序类,因为它不是OOP(OOP Alternative to Utility Classes)。
答案 1 :(得分:1)
虽然我认为静态实用程序方法不一定是Bad Thing™,但您应该了解这些方法的语义。这里最重要的一点是static
意味着方法可能不参与任何形式的多态。那就是:它可能不会被覆盖。
因此,关于设计,第二种选择提供了更大程度的灵活性。
附注:即使您选择第二种方法,最终也可能在内部调度到(非公开的)静态方法:
class Mover {
private final List<? extends Mobile> mobiles;
public void updatePositions(){
MyStaticUtilityMethods.updatePositions(this.mobiles);
}
}
请注意,我一般不会推荐这个,但在许多情况下将其指出是一个可能合理的选项。
这可能是偏离主题的,但这里的设计还有另一个自由度。您可以(并且至少应该考虑)更进一步:只要可以从方法名称猜测(!),您可以考虑使用接口PositionUpdater
和CollisionDetector
。然后,您可以在Mover
类中存储实现这些接口的类的实例,并将实际调用分派给这些接口。这样,您就可以轻松地将“Mover”组成的不同方面结合起来。
(我知道,这并没有回答实际问题。事实上,它只是“推迟”它是PositionUpdater
是应该接收数据作为参数,还是在施工时接收它们......)< / p>
然后,您可以将PositionUpdater
接口的不同实现的实例分配给Mover
实例。例如,您可以使用名为LinearMovementPositionUpdater
和RandomWalkPositionUpdater
的具体类。将这些类的实例(它们都实现了PositionUpdater
接口)传递给Mover
,可以让您更改Mover
实现的一个方面 - 基本上,无需触及任何代码! (你甚至可以在运行时更改 !)。
这样,responsibilities为
显然是封装的。
但是,这只是一个提示。判断这种方法在一个特定情况下是否合理且适用是软件工程师获得所有$$$的原因。
答案 2 :(得分:1)
你在这里遇到的问题主要是由于有一个精心设计的模型(并且它可能伴随着一个贫血的领域模型)。
如果您使用事件驱动方法,这些方法将简单地消失并被事件处理程序替换,每个事件处理程序将独立于另一个响应适当的事件,从初始事件中获取所需的任何信息。
这意味着您不必处理传递参数或确定要传递的参数 - 每个'处理程序(方法)'都知道它需要什么并且会接受它,而不是必须有一个外部协调器了解需要哪些数据并将其传递。
orchestrator模型通过让它“了解”它正在编排的组件的信息需求来打破封装。
现在,这不是特定于java的问题。它适用于大多数现代面向对象语言。如果你正在使用java,c-sharp或c ++,这没关系。这是一般模式。
要脱离这种想法,请阅读DDD(领域驱动设计)和事件采购。