我正在设计一款游戏,并且对我正在做的事情有很好的了解。
然而,我一直在努力提高自己的OOP技能但是我现在面临同样的问题,我应该如何使用抽象的对象?
假设我有一个实体列表,它代表屏幕上有x和y属性的任何东西,可能宽度和高度还没有全部用完!
然后我有一些特殊类型的实体,一个可以移动,一个不能,也可能是将来可以碰撞的东西。
它们都在实体集合中(在我的情况下是List<Entity>
)现在我想模拟移动的实体并且是主循环上的DynamicEntity实例,但它们都在实体的抽象列表中我不知道循环中的实体是否为动态实体。
我知道我可以用instanceof
检查一下,但我很确定这不是最好的主意..
我看到有些人在Entity中有类似boolean的东西来检查它的类型,但我真的不想在那里对所有类型的实体进行硬编码。
我只是想知道这种情况下的最佳做法是什么?
答案 0 :(得分:5)
通常最好避免在可能的情况下检查类型。如果您认为需要在代码中使用instanceof
,那么可能会使用抽象来使您的设计更具可扩展性。 (如果您决定在将来添加第三种类型的Entity
,则不希望必须返回并使用第三种情况更新所有instanceof
次检查。)
有两种常见的方法可以根据实例的具体类型进行不同的操作,而无需检查具体类型:
一种常见的方式是visitor pattern。这里的想法是创建一个Visitor类,其中包含每种类型对象的操作。接下来,每个具体类都有一个accept
方法,它只是在访问者类中调用正确的visit
方法。这种单向间接允许对象自己选择正确的操作,而不是通过检查类型来选择它。
访客模式通常用于以下两个原因之一。 1)您可以向实现访问者模式的类层次结构添加新操作,而无需访问类的源代码。您只需要实现一个新的访问者类,并将其与可访问类的预先存在的accept
方法结合使用。 2)当有许多可能的动作可以对某些类型层次结构的类执行时,有时将每个动作拆分为它自己的访问者类更清楚,而不是用一堆方法对一组不同的动作污染目标类,所以你用访问者而不是目标类对它们进行分组。
但是,在大多数情况下,以第二种方式执行操作更容易:简单地覆盖每个具体类中的公共方法的定义。 Entity
类可能有一个抽象的draw()
方法,然后每种类型的实体都会以不同的方式实现该draw()
方法。您知道每种类型的实体都有一个可以调用的draw()
方法,但您不必知道实体的类型或方法的实现方式的详细信息。您所要做的就是遍历List<Entity>
并在每个draw()
上调用draw()
,然后他们会根据类型执行正确的操作,因为每种类型都有自己的专用{{1}}实施
答案 1 :(得分:2)
你是对的,你不想检查实例类型或具有某种功能来检查功能。我的第一个问题是 - 为什么你首先要有一个基本类型的实体列表?听起来像你需要维护一个动态实体列表。
也许最好实现一个触发该列表迭代的事件,并依次将该事件传递给每个对象。动态实体可以决定继续该事件。静态实体显然不会。
e.g。
move()
在这种情况下,您可以使用不同的事件类型,实体将根据事件类型和实体类型决定其操作。这称为双重调度或visitor pattern。
答案 2 :(得分:1)
如果您对实体的处理依赖于了解有关实体类型的详细信息,那么您的Entity
抽象不会对您造成太大的影响(至少在这个用例中没有):您的List<Entity>
几乎是因为仅仅List<Object>
而对你不透明。
如果您知道您可以想象的每个实体都是静态的或动态的,那么对所有实体都有一个布尔属性没有“硬编码”:isDynamic()
或者什么。
但是,如果动态方面仅对您的实体子集有意义,那么这个标志确实会给您的抽象带来一些麻烦。在这种情况下,我的第一个猜测是你没有正确建模用例,因为你需要处理一些没有提供足够的多态信息的项目列表来处理它们。