Я столкнулся с проблемой в игре, которую я делаю на C#. Это простая игра на основе плитки, и проблема возникла из-за того, что я пытаюсь сделать следующее:Использование GetType/instanceof в C# по сравнению с альтернативами
Скажем, у нас есть основные типы плитки, круги и бриллианты, которые являются подклассами Плитки. Вместо того, чтобы круги только соответствовали кругам, я попытался извлечь поведение «совпадений» в абстрактный метод Tile: canMatchWith (Tile t). Плитки также имеют два способа добавить/удалить плитки, с которыми они могут сравниться.
Так скажите, что у нас есть круглая черепица в середине нашей игры, и у нас есть powerup, в котором говорится: «Круги на круге могут совпадать с квадратными черепицами в этом повороте». Я бы прошел через все плитки Circle и сказал circleTile.addCanMatchWith (typeof (Square)). Внутри у нас есть список canMatchWith.
Затем я хочу сказать: «Круги больше не могут совпадать с квадратами» и просто сказать circleTile.removeCanMatchWith (typeOf (Square)).
Это мое текущее решение, и оно отлично работает с недостатками производительности, которые я заметил (это игра на основе плитки, поэтому эти типы оцениваются только один раз за «ход», а не за кадром). Тем не менее, голос в моей голове говорит мне, что это плохой способ выполнить это поведение. Поэтому у меня есть несколько альтернатив:
- Enums ... Каждая плитка может состоять из переменной типа Tiletype. Это будет инициализировано в конструкторе и задано Type.SQUARE для квадратов и т. Д. Затем каждая Плитка будет иметь список canMatchWith, а функциональность такая же, как и моя первоначальная реализация. За исключением этого случая, это немного сложнее. Скажем, у меня есть некоторые подклассы окружности, овальные и elipse. Я хочу, чтобы овалы могли соответствовать ТОЛЬКО квадратам, но elipses могут соответствовать всем кругам, а не квадратам.
Проблема здесь является избыточность, мой перечисление будет теперь Овальные и ELIPSE, а также и класс Elipse бы (круг, овал, ELIPSE TileTypes) в качестве типов он может сравниться с. Это полностью избыточно, я хочу просто сказать «Круг», который я мог бы с помощью типов. Я полагаю, что Tiles может иметь TileType baseType и TileType actualType.
- Некоторая форма поведения. Забудьте подклассы Tile, просто укажите методы Tiles и переменную экземпляра для List. Затем во время выполнения мы можем просто сказать someTile.addCanMatch (новый CircleMatchBehavior()). Это кажется глупым, поскольку у меня будет куча классов, просто говорящих, что вы можете соответствовать определенной форме.
Таким образом, я пытаюсь добиться того, чтобы несколько типов объектов могли взаимодействовать с любым количеством разных типов. Вопрос в том, что я должен использовать для Типа. Можно ли использовать GetType здесь? Перечни? Или есть лучшая стратегия, которую кто-то порекомендовал бы? Я стараюсь быть как можно более общим, эти плитки не должны иметь каких-либо жестко закодированных зависимостей от других фрагментов и должны иметь возможность изменять, с кем они могут взаимодействовать «на лету». Скажем, я делаю новый подкласс подкласса, пентагон ... ну, Pentagons могут совпадать с квадратами, кругами и Pentagons. Легко с моей реализацией, но что-то говорит мне, что это грязная практика ООП.
Мне кажется, что я должен использовать типы/перечисления, потому что я не пытаюсь сказать thisTile.addCanMatch (Tile someOtherObject). Это слишком специфично, я хочу, чтобы thisTile мог сопоставляться со всеми фрагментами, которые являются экземплярами определенного класса.
Я боюсь, что я не достаточно опытный дизайнер, чтобы предложить полный дизайн для вас, но если не фактические * * функциональные различия в способе кругов и Овалы работают, может быть лучше иметь все экземпляры класса 'Tile', а затем установить какой-то атрибут' Behavior'. Все круги на доске могут совместно использовать один и тот же объект 'Behavior', а затем, когда правила изменяются для поворота, вы можете установить изменения на этом объекте' Behavior'. Это может привести к меньшему дублированию кода, если я понимаю ситуацию. – Katana314
Если я правильно понимаю вас, это похоже на мой № 2 Поведение. Мой страх здесь - это взрыв поведения. Например, MatchesWithCirclesAndSquaresBehavior. Посмотрите, что я получаю? Если есть 5 типов плиток, тогда у нас есть 5 выбрать 1 плюс 5 выбрать 2 плюс 5 выбрать 3 плюс 5 выбрать 4 плюс 5 выбрать 5 комбинаций поведения. Это кажется еще хуже, чем GetType. Однако я мог бы не понимать что-то в вашем предложении. Плитки сами делают все, что хотят, можно сделать анимацию взрыва и т. Д. Это только потому, что плитка может совпадать с другой. – user2045279
Я не предлагал Поведение быть Enum или не поддающимся модификации классу. Вы можете подклассифицировать его способами, но в первую очередь я ожидаю, что он будет иметь внутреннюю коллекцию, представляющую тип (Circle) и типы (ы), которые он может сопоставить (квадрат). Затем вы можете изменить это с точки зрения данных. Я определенно согласен с тем, что все, что приведет к массивным блокам if/else/switch, следует избегать в пользу хорошей настройки объекта, но мы также хотим избежать написания нового класса для учета некоторых не очень новых изменений в поведении. – Katana314