Альтернатива instanceof? - PullRequest
       8

Альтернатива instanceof?

2 голосов
/ 19 апреля 2011

Я слышал, что это плохой дизайн - использовать instanceof или эквивалент (http://www.javapractices.com/topic/TopicAction.do?Id=31, , когда мы должны использовать instanceof, а когда нет ), с которым я могу согласиться, главным образом потому, что он может сделать код трудно использовать повторно.

Однако в некоторых случаях мне было трудно найти хорошую альтернативу instanceof. Например, скажем, что я хочу создать стратегию в реальном времени. Игра состоит из препятствий, зданий и танков, все они размещены на сетке, и каждое право занимает ровно одну единицу в сетке. Поэтому я создаю класс Entity, который является суперклассом классов Obstacle, Building и Tank. Сетка состоит из экземпляров Entity. Во время каждого обновления я хочу, чтобы каждый танк прицеливался и стрелял по вражескому танку в пределах досягаемости. Таким образом, простым способом сделать это было бы для каждого танка запросить сетку для всех сущностей в пределах диапазона танков, а затем выполнить итерацию по всем этим сущностям и проверить, являются ли они экземпляром класса Tank.

Моя единственная попытка в качестве альтернативы использования instanceof состояла в том, чтобы использовать шаблон проектирования Visitor . Посетитель получает подтверждение от лица (entity->acceptVisitor(visitor)), которое, в свою очередь, вызывает один из методов visitor->visitObstacle(this), visitor->visitBuildig(this) или visitor->visitTank(this). Это, однако, вынудило меня создать много посетителей, почти по одному новому для каждой задачи, которую я хотел сделать на объектах. Другая проблема заключается в том, что во многих случаях посетитель вызывает один и тот же метод для объекта, независимо от того, из какого класса он построен. Например, это может произойти, когда объект хочет проверить, является ли другой объект стационарным или нет:

Код Python:

class StationaryEntityGatherVisitor:
    def __init__(self):
        self.stationaryEntities = []

    def visitObstacle(self, obstacle):
        self._addIfStationary( obstacle )

    def visitBuildig(self, building):
        self._addIfStationary( building )

    def visitTank(self, tank):
        self._addIfStationary( tank )

    def _addIfStationary(self, entity):
        if entity.isStationary():
            self.stationaryEntities.append( entity )

    def getStationaryEntities():
        return self.stationaryEntities

Я мог бы, конечно, позволить сущности в этом случае просто спросить другую сущность, является ли она неподвижной напрямую, вместо того, чтобы позволить посетителю сделать это. Но в этом случае я не был бы последовательным при проверке свойств объектов. Разрешить варьировать метод опроса сущностей о каком-либо свойстве (напрямую или через посетителя), в зависимости от того, нужно ли мне проверять тип сущностей или нет, на мой взгляд, это выглядит довольно странно.

Итак, у вас есть другая альтернатива использованию instanceof в описанной выше проблеме?

Спасибо! Martin

Ответы [ 4 ]

1 голос
/ 19 апреля 2011

Забудьте о своем решении для посетителей на секунду и сконцентрируйтесь только на своем требовании:

Сетка состоит из экземпляров Entity.Во время каждого обновления я хочу, чтобы каждый танк прицеливался и стрелял по вражескому танку в пределах досягаемости.Таким образом, простым способом сделать это было бы для каждого танка запросить сетку для всех сущностей в пределах диапазона танков, а затем выполнить итерацию по всем этим сущностям и проверить, являются ли они экземпляром класса Tank.

Почему бы просто не отфильтровать список напрямую?

targetablesInRange = filter(isTargetable, grid.itemsInRangeOf(self))

Вместо просто танков, вам следует спросить о свойстве сущностей, которое делает их целью.Это может вернуть false в базовом классе и быть переопределено Tank и другими классами, которые вы представите позже, и которые должны быть запущены.

0 голосов
/ 19 апреля 2011

В общем, полиморфизм - это способ избежать ненужного экземпляра оператора.

0 голосов
/ 19 апреля 2011

Я не знаю, нужно ли вам использовать Visitor для обработки этого поведения.Ваш случай может быть очень легко осуществлен с использованием общего полиморфизма.Сначала я собирался предложить фабричный метод и переменную типа, но решение может быть еще проще.

Итак, у вас есть общий абстрактный суперкласс.(Сущность).Таким образом, в этом классе вы можете определить метод с именем hitByMissile () (или любой другой).В своем классе танков вы можете сделать hitByMissile, отличающийся от, скажем, препятствия.Ваш код не должен определять, как ведет себя каждая сущность.Поведение должно определяться самим объектом.Таким образом, вы можете просто перебирать объекты и вызывать метод.

0 голосов
/ 19 апреля 2011

Хорошо, вы рассматривали возможность итераций по всем танкам, чтобы увидеть, находятся ли они в радиусе действия, а не по всем сущностям в радиусе, чтобы увидеть, являются ли они танками?Похоже, это сэкономит вам много времени на итерации и вызовах instanceof ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...