Избегайте использования InstanceOf с шаблоном посетителя - Java
Я искал об этом объекте в Stack Overflow. Я нашел следующее решение:
Теперь мой случай похож на этот. Мне нужно, однако, чтобы избежать использования "instanceOf
".
У меня есть игра, в которой названы башни MonkeyTower
, CannonTower
, OctoTower
... и некоторые другие классы используют instanceOf
сравнивать.
Вот пример класса, который использует instanceOf
:
BloonsTower.java
public void mousePressed(Point p) {
Tower t = null;
selectedTower = towerInfo[ insertTowerIdx ].getTower();
if( selectedTower instanceof MonkeyTower )
t = tCreator.createMonkey();
else if( selectedTower instanceof OctoTower )
t = tCreator.createOctogonal();
else if( selectedTower instanceof CannonTower )
t = tCreator.createCannon();
else if( selectedTower instanceof MortarTower )
t = tCreator.createMortar();
setMoney( money - towerInfo[ insertTowerIdx ].getPrice() );
t.setPosition( p );
world.addTower(t);
currentState = new SelectTowerState();
}
ManipulatorCreator.java
if( t instanceof MonkeyTower )
return null;
else if( t instanceof OctoTower )
return new OctoManipulator( t );
else if( t instanceof CannonTower )
return null;
else if( t instanceof MortarTower )
return new MortarManipulator( (MortarTower)t );
return man;
И GameWriter:
public void saveFile( File file, int round, int money, int lives, World m ) throws IOException {
PrintWriter out = new PrintWriter( new BufferedWriter( new FileWriter( file) ) );
out.println( round );
out.println( money );
out.println( lives );
Tower []torres = m.getTowers();
out.println( torres.length ); // escrever o nº de torres
for( Tower t : torres ){
Point p = t.getComponent().getPosicao();
// escrever a posição e o tipo de torre
out.print(p.x+"\t" + p.y+"\t" );
if( t instanceof MonkeyTower )
out.println( "macaco" );
else if( t instanceof OctoTower )
out.println( "octo" );
else if( t instanceof CannonTower )
out.println( "canhao" );
else if( t instanceof MortarTower )
out.println( "morteiro" );
}
out.close();
}
Я создал класс для посетителя, который посещает каждую башню:
public class TowerVisitor implements Visitor{
public void visit(MonkeyTower monkey) {
// TODO Auto-generated method stub
}
public void visit(CannonTower cannon) {
// TODO Auto-generated method stub
}
public void visit(MortarTower mortar) {
// TODO Auto-generated method stub
}
public void visit(OctoTower octo) {
// TODO Auto-generated method stub
}
}
И в каждой башне, которую я создал, есть метод accept
это возвращает себя
Теперь я застрял в том, что положить в метод visit
и как использовать шаблон для переключения всех instanceOf
"S.
Благодарю.
3 ответа
Вы должны использовать основные шаблоны объектно-ориентированного программирования, а именно наследование, а не шаблон посетителя. У вас есть несколько различных типов башен и аналогичные действия (создание, управление, toString и т. Д.), Которые должны быть реализованы по-разному для каждого типа башни. Классический пример наследования.
public abstract class Tower {
public abstract Tower create();
public abstract Manipulator manipulate();
}
---
public class MortarTower extends Tower {
@Override
public MortarTower create() {
return new MortarTower();
}
@Override
public MortarManipulator manipulate() {
return new MortarManipulator(this);
}
@Override
public String toString() {
return "morteiro";
}
}
---
public void mousePressed(Point p) {
selectedTower = towerInfo[insertTowerIdx].getTower();
setMoney(money - towerInfo[insertTowerIdx].getPrice());
Tower t = selectedTower.create();
t.setPosition(p);
world.addTower(t);
currentState = new SelectTowerState();
}
И так далее.
Если вы хотите делать все с посетителями, вам нужно создавать посетителей для каждого случая, т.е. для создания башни и манипулятора и для сохранения файла. Также я думаю, что в этом случае вам не нужно создавать метод accept для каждой башни, но вы можете. Метод Accept получит некоего общего посетителя, и все, что он будет делать, это просто вызвать метод visitor.visit. Что-то вроде:
public class CannonTower {
public void accept(CommonVisitor visitor) {
visitor.visit(this);
}
}
Создайте общий интерфейс посетителя с пустыми методами:
public interface CommonVisitor {
default void visit(MonkeyTower monkey) {
// nothing to do to not implement when it is not required at all
}
default void visit(CannonTower cannon) {
// nothing to do
}
default void visit(MortarTower mortar) {
// nothing to do
}
default void visit(OctoTower octo) {
// nothing to do
}
}
Давайте создадим посетителя для BloonsTower.java для создания башен (имхо ваш код выглядит немного странно - вы получаете башню и создаете такую же башню):
@Getter
public class TowerCreatorVisitor implements CommonVisitor {
public TowerCreatorVisitor(TowerCreator tCreator) {
this.tCreator = tCreator;
}
TowerCreator tCreator;
Tower tower;
public void visit(MonkeyTower monkey) {
tower = tCreator.createMonkey();
}
public void visit(CannonTower cannon) {
tower = tCreator.createCannon();
}
public void visit(MortarTower mortar) {
tower = tCreator.createMortar();
}
public void visit(OctoTower octo) {
tower = tCreator.createOcto();
}
}
BloonsTower.java стал:
public void mousePressed(Point p) {
Tower t = null;
selectedTower = towerInfo[ insertTowerIdx ].getTower();
TowerCreatorVisitor towerCreatorVisitor = new TowerCreatorVisitor(tCreator);
selectedTower.accept(towerCreatorVisitor);
// you may not use accept at all, then just
// towerCreatorVisitor.visit(selectedTower);
// up to you)
t = towerCreatorVisitor.getTower();
setMoney( money - towerInfo[ insertTowerIdx ].getPrice() );
t.setPosition( p );
world.addTower(t);
currentState = new SelectTowerState();
}
Чтобы создать манипулятор:
@Getter
public class ManipulatorCreatorVisitor implements CommonVisitor {
Manipulator manipulator = new Manipulator();
public void visit(MonkeyTower monkey) {
tower = null;
}
public void visit(CannonTower cannon) {
tower = null;
}
public void visit(MortarTower mortar) {
manipulator = new MortarManipulator(mortar);
}
public void visit(OctoTower octo) {
manipulator = new OctoManipulator(octo);
}
}
Создатель маниплатора:
public Manipulator getManipulator(Tower t) {
ManipulatorCreatorVisitor manipulatorCreatorVisitor = new ManipulatorCreatorVisitor();
t.accept(manipulatorCreatorVisitor);
return manipulatorCreatorVisitor.getManipulator();
}
Чтобы сохранить файл:
@AllArgsConstructor
public class FileWriterVisitor implements CommonVisitor {
PrintWriter out;
public void visit(MonkeyTower monkey) {
out.println( "macaco" );
}
public void visit(CannonTower cannon) {
out.println( "canhao" );
}
public void visit(MortarTower mortar) {
out.println( "morteiro" ); }
public void visit(OctoTower octo) {
out.println( "octo" ); }
}
Автор игры:
public void saveFile( File file, int round, int money, int lives, World m ) throws IOException {
PrintWriter out = new PrintWriter( new BufferedWriter( new FileWriter( file) ) );
out.println( round );
out.println( money );
out.println( lives );
Tower []torres = m.getTowers();
out.println( torres.length ); // escrever o nº de torres
FileWriterVisitor fileWriterVisitor = new FileWriterVisitor(out);
for( Tower t : torres ){
Point p = t.getComponent().getPosicao();
// escrever a posição e o tipo de torre
out.print(p.x+"\t" + p.y+"\t" );
fileWriterVisitor.visit(t);
// or t.accept(fileWriterVisitor);
}
out.close();
}
Вы должны использовать FactoryMethod
или же AbstractFactory
шаблон (если вы хотите создать ManipulatorDactory независимо от Tower) вместо Visitor.
Взгляните на этот Factory Method и Abstract Facotry для более подробной информации.
Пример кода:
public class FactoryMethodDemo{
public FactoryMethodDemo(){
}
public Tower getTower(String type){
if ( type.equalsIgnoreCase("monkey")){
return new MonkeyTower();
}else if ( type.equalsIgnoreCase("octo")){
return new OctoTower();
}else if ( type.equalsIgnoreCase("canon")){
return new CannonTower();
}else if ( type.equalsIgnoreCase("mortal")){
return new MortarTower();
}
return null;
}
public static void main(String args[]){
FactoryMethodDemo factory = new FactoryMethodDemo();
Tower tower = factory.getTower(args[0]);
System.out.println("Tower:"+tower);
}
}
abstract class Tower{
Manipulator manipulator = null;
public Tower(){
}
public String toString(){
return this.getClass().getSimpleName()+":manipulator:"+manipulator;
}
public Manipulator getManipulator(){
return manipulator;
}
}
class MonkeyTower extends Tower{
public MonkeyTower(){
}
}
class OctoTower extends Tower{
public OctoTower(){
manipulator = new OctoManipulator();
}
}
class CannonTower extends Tower{
public CannonTower(){
}
}
class MortarTower extends Tower{
public MortarTower(){
manipulator = new MortarManipulator();
}
}
class Manipulator{
}
class OctoManipulator extends Manipulator{
}
class MortarManipulator extends Manipulator{
}
выход:
D:\Study\Java>java FactoryMethodDemo monkey
Tower:MonkeyTower:manipulator:null
D:\Study\Java>java FactoryMethodDemo mortal
Tower:MortarTower:manipulator:MortarManipulator@4187a8e0
D:\Study\Java>java FactoryMethodDemo octo
Tower:OctoTower:manipulator:OctoManipulator@46fb3d6
D:\Study\Java>java FactoryMethodDemo canon
Tower:CannonTower:manipulator:null
Связанные вопросы SE:
Заводская модель. Когда использовать фабричные методы?
В чем принципиальная разница между фабричными и абстрактными фабричными моделями?