我正在尝试实现我的第一个工厂设计模式,但不确定将工厂制造的对象添加到列表时如何避免使用instanceof。这就是我想要做的:
for (ABluePrint bp : bluePrints) { AVehicle v = AVehicleFactory.buildVehicle(bp); allVehicles.add(v); // Can I accomplish this without using 'instanceof'? if (v instanceof ACar) { cars.add((ACar) v); } else if (v instanceof ABoat) { boats.add((ABoat) v); } else if (v instanceof APlane) { planes.add((APlane) v); } }
根据我在SO上阅读的内容,使用“ instanceof”是一种代码味道。有没有一种更好的方法可以检查工厂创建的不使用“ instanceof”的车辆类型?
我欢迎任何有关实施的反馈/建议,因为我什至不确定我是否会采用正确的方法。
完整示例如下:
import java.util.ArrayList; class VehicleManager { public static void main(String[] args) { ArrayList<ABluePrint> bluePrints = new ArrayList<ABluePrint>(); ArrayList<AVehicle> allVehicles = new ArrayList<AVehicle>(); ArrayList<ACar> cars = new ArrayList<ACar>(); ArrayList<ABoat> boats = new ArrayList<ABoat>(); ArrayList<APlane> planes = new ArrayList<APlane>(); /* * In my application I have to access the blueprints through an API * b/c they have already been created and stored in a data file. * I'm creating them here just for example. */ ABluePrint bp0 = new ABluePrint(0); ABluePrint bp1 = new ABluePrint(1); ABluePrint bp2 = new ABluePrint(2); bluePrints.add(bp0); bluePrints.add(bp1); bluePrints.add(bp2); for (ABluePrint bp : bluePrints) { AVehicle v = AVehicleFactory.buildVehicle(bp); allVehicles.add(v); // Can I accomplish this without using 'instanceof'? if (v instanceof ACar) { cars.add((ACar) v); } else if (v instanceof ABoat) { boats.add((ABoat) v); } else if (v instanceof APlane) { planes.add((APlane) v); } } System.out.println("All Vehicles:"); for (AVehicle v : allVehicles) { System.out.println("Vehicle: " + v + ", maxSpeed: " + v.maxSpeed); } System.out.println("Cars:"); for (ACar c : cars) { System.out.println("Car: " + c + ", numCylinders: " + c.numCylinders); } System.out.println("Boats:"); for (ABoat b : boats) { System.out.println("Boat: " + b + ", numRudders: " + b.numRudders); } System.out.println("Planes:"); for (APlane p : planes) { System.out.println("Plane: " + p + ", numPropellers: " + p.numPropellers); } } } class AVehicle { double maxSpeed; AVehicle(double maxSpeed) { this.maxSpeed = maxSpeed; } } class ACar extends AVehicle { int numCylinders; ACar(double maxSpeed, int numCylinders) { super(maxSpeed); this.numCylinders = numCylinders; } } class ABoat extends AVehicle { int numRudders; ABoat(double maxSpeed, int numRudders) { super(maxSpeed); this.numRudders = numRudders; } } class APlane extends AVehicle { int numPropellers; APlane(double maxSpeed, int numPropellers) { super(maxSpeed); this.numPropellers = numPropellers; } } class AVehicleFactory { public static AVehicle buildVehicle(ABluePrint blueprint) { switch (blueprint.type) { case 0: return new ACar(100.0, 4); case 1: return new ABoat(65.0, 1); case 2: return new APlane(600.0, 2); default: return new AVehicle(0.0); } } } class ABluePrint { int type; // 0 = car; // 1 = boat; // 2 = plane; ABluePrint(int type) { this.type = type; } }
您可以实现Visitor模式。
详细答案
这个想法是使用多态来执行类型检查。每个子类都覆盖该accept(Visitor)方法,该方法应在超类中声明。当我们遇到如下情况时:
void add(Vehicle vehicle) { //what type is vehicle?? }
我们可以将一个对象传递到中声明的方法中Vehicle。如果vehicle类型为Car,并class Car覆盖我们将对象传递给的方法,则该对象现在将在Car类中声明的方法内进行处理。我们利用它的优势:创建一个Visitor对象并将其传递给重写的方法:
abstract class Vehicle { public abstract void accept(AddToListVisitor visitor); } class Car extends Vehicle { public void accept(AddToListVisitor visitor) { //gets handled in this class } }
这Visitor应该准备好访问类型Car。您想要避免使用的任何类型instanceof都必须在中指定Visitor。
class AddToListVisitor { public void visit(Car car) { //now we know the type! do something... } public void visit(Plane plane) { //now we know the type! do something... } }
这是类型检查的地方!
当Car接收到访问者时,它应该使用this关键字传递自己。由于我们在class中Car,因此visit(Car)将调用该方法。现在我们知道了对象的类型,就可以在访问者内部执行所需的操作。
因此,从顶部开始:
您创建一个Visitor,执行所需的操作。访问者应该visit为要对其执行操作的每种对象类型提供一个方法。在这种情况下,我们正在为车辆创建访客:
interface VehicleVisitor { void visit(Car car); void visit(Plane plane); void visit(Boat boat); }
我们要执行的动作是将车辆添加到某物上。我们将创建一个AddTransportVisitor;负责管理交通运输的访客:
class AddTransportVisitor implements VehicleVisitor { public void visit(Car car) { //add to car list } public void visit(Plane plane) { //add to plane list } public void visit(Boat boat) { //add to boat list } }
每辆车都应该能够接纳来访者:
abstract class Vehicle { public abstract void accept(VehicleVisitor visitor); }
当访客被传递到车辆时,车辆应调用其visit方法,并将自身传递给参数:
class Car extends Vehicle { public void accept(VehicleVisitor visitor) { visitor.visit(this); } } class Boat extends Vehicle { public void accept(VehicleVisitor visitor) { visitor.visit(this); } } class Plane extends Vehicle { public void accept(VehicleVisitor visitor) { visitor.visit(this); } }
这就是类型检查的地方。visit会调用正确的方法,该方法包含根据方法的参数执行的正确代码。
最后一个问题是VehicleVisitor与列表进行交互。这就是您的VehicleManager来历:它封装了列表,使您可以通过一种VehicleManager#add(Vehicle)方法添加载具。
创建访问者时,我们可以将管理器传递给它(可能通过它的构造函数),这样,既然我们知道对象的类型,就可以执行所需的操作。本VehicleManager应包含的游客和拦截VehicleManager#add(Vehicle)来电:
class VehicleManager { private List<Car> carList = new ArrayList<>(); private List<Boat> boatList = new ArrayList<>(); private List<Plane> planeList = new ArrayList<>(); private AddTransportVisitor addVisitor = new AddTransportVisitor(this); public void add(Vehicle vehicle) { vehicle.accept(addVisitor); } public List<Car> getCarList() { return carList; } public List<Boat> getBoatList() { return boatList; } public List<Plane> getPlaneList() { return planeList; } }
现在,我们可以为这些AddTransportVisitor#visit方法编写实现:
class AddTransportVisitor implements VehicleVisitor { private VehicleManager manager; public AddTransportVisitor(VehicleManager manager) { this.manager = manager; } public void visit(Car car) { manager.getCarList().add(car); } public void visit(Plane plane) { manager.getPlaneList().add(plane); } public void visit(Boat boat) { manager.getBoatList().add(boat); } }
我强烈建议删除add每种车辆的吸气剂方法并声明重载方法。这样可以减少不需要时的“访问”开销,例如manager.add(new Car()):
class VehicleManager { private List<Car> carList = new ArrayList<>(); private List<Boat> boatList = new ArrayList<>(); private List<Plane> planeList = new ArrayList<>(); private AddTransportVisitor addVisitor = new AddTransportVisitor(this); public void add(Vehicle vehicle) { vehicle.accept(addVisitor); } public void add(Car car) { carList.add(car); } public void add(Boat boat) { boatList.add(boat); } public void add(Plane plane) { planeList.add(plane); } public void printAllVehicles() { //loop through vehicles, print } } class AddTransportVisitor implements VehicleVisitor { private VehicleManager manager; public AddTransportVisitor(VehicleManager manager) { this.manager = manager; }