在实施工厂设计模式时如何避免“instanceof”? [英] How to avoid 'instanceof' when implementing factory design pattern?
问题描述
我正在尝试实现我的第一个工厂设计模式,我不知道如何在将工厂制作的对象添加到列表中时避免使用instanceof。这就是我要做的:
I am attempting to implement my first Factory Design Pattern, and I'm not sure how to avoid using instanceof when adding the factory-made objects to lists. This is what I'm trying to do:
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'?
From what I've read on SO, using 'instanceof' is a code smell. Is there a better way to check the type of vehicle that was created by the factory without using 'instanceof'?
我欢迎任何关于我的实施的反馈/建议,甚至不知道我是否正确的做到这一点。
I welcome any feedback/suggestions on my implementation as I'm not even sure if I'm going about this the right way.
以下全部示例:
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;
}
}
推荐答案
你可以实施访客模式。
详细答案
想法是使用多态进行类型检查。每个子类覆盖 c> accept(Visitor)方法,该方法应在超类中声明。当我们有这样的情况:
The idea is to use polymorphism to perform the type-checking. Each subclass overrides the accept(Visitor)
method, which should be declared in the superclass. When we have a situation like:
void add(Vehicle vehicle) {
//what type is vehicle??
}
我们可以将对象传递到车辆
。如果车辆
的类型为 Car
,而 class Car
overrode我们传递对象的方法,该对象现在将在 Car
类中声明的方法中处理。我们使用这个来获取优势:创建一个访问者
对象并将其传递给覆盖方法:
We can pass an object into a method declared in Vehicle
. If vehicle
is of type Car
, and class Car
overrode the method we passed the object into, that object would now be processed within the method declared in the Car
class. We use this to our advantage: creating a Visitor
object and pass it to an overriden method:
abstract class Vehicle {
public abstract void accept(AddToListVisitor visitor);
}
class Car extends Vehicle {
public void accept(AddToListVisitor visitor) {
//gets handled in this class
}
}
这个访客
应该准备访问键入 Car
。您想避免使用 instanceof
来查找实际类型的任何类型必须在 Visitor
中指定。
This Visitor
should be prepared to visit type Car
. Any type that you want to avoid using instanceof
to find the actual type of must be specified in the 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
收到访问者时,它应该使用这个
关键字。由于我们在课程 Car
中,将调用方法访问(Car)
。在我们的访客内部,我们可以执行我们想要的动作,现在我们知道对象的类型。
When the Car
receives the visitor, it should pass itself in using the this
keyword. Since we are in class Car
, the method visit(Car)
will be invoked. Inside of our visitor, we can perform the action we want, now that we know the type of the object.
所以,从顶部:
您创建一个访问者
,执行您想要的操作。一个访问者应该包含一个访问
方法,为每个类型的对象执行一个操作。在这种情况下,我们正在为车辆创建访客:
You create a Visitor
, which performs the actions you want. A visitor should consist of a visit
method for each type of object you want to perform an action on. In this case, we are creating a visitor for vehicles:
interface VehicleVisitor {
void visit(Car car);
void visit(Plane plane);
void visit(Boat boat);
}
我们要执行的操作是将车辆添加到某物。我们将创建一个 AddTransportVisitor
;管理添加运输的访问者:
The action we want to perform is adding the vehicle to something. We would create an AddTransportVisitor
; a visitor that manages adding transportations:
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
}
}
每个车辆都应该能够接受车辆游客:
Every vehicle should be able to accept vehicle visitors:
abstract class Vehicle {
public abstract void accept(VehicleVisitor visitor);
}
当访问者被传递到车辆时,车辆应该调用它的访问
方法,将自身传入参数:
When a visitor is passed to a vehicle, the vehicle should invoke it's visit
method, passing itself into the arguments:
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);
}
}
这是类型检查发生的地方。调用正确的访问
方法,其中包含基于方法参数执行的正确代码。
That's where the type-checking happens. The correct visit
method is called, which contains the correct code to execute based on the method's parameters.
最后一个问题在于使用 VehicleVisitor
与列表进行交互。这是您的 VehicleManager
的地方:它封装列表,允许您通过 VehicleManager#add(Vehicle)$ c $添加车辆c>方法
The last problem is having the VehicleVisitor
interact with the lists. This is where your VehicleManager
comes in: it encapsulates the lists, allowing you to add vehicles through a VehicleManager#add(Vehicle)
method.
当我们创建访问者时,我们可以将经理传递给它(可能通过它的构造函数),所以我们可以执行我们想要的动作,现在我们知道对象的类型。 VehicleManager
应该包含访问者和截取 VehicleManager#add(Vehicle)
call:
When we create the visitor, we can pass the manager to it (possibly through it's constructor), so we can perform the action we want, now that we know the object's type. The VehicleManager
should contain the visitor and intercept VehicleManager#add(Vehicle)
calls:
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#访问
方法:
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);
}
}
我强烈建议删除getter方法并声明重载 add
每种类型车辆的方法。这将减少不需要访问的开销,例如 manager.add(new Car())
:
I highly suggest removing the getter methods and declaring overloaded add
methods for each type of vehicle. This will reduce overhead from "visiting" when it's not needed, for example, 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;
}
public void visit(Car car) {
manager.add(car);
}
public void visit(Plane plane) {
manager.add(plane);
}
public void visit(Boat boat) {
manager.add(boat);
}
}
public class Main {
public static void main(String[] args) {
Vehicle[] vehicles = {
new Plane(),
new Car(),
new Car(),
new Car(),
new Boat(),
new Boat()
};
VehicleManager manager = new VehicleManager();
for(Vehicle vehicle : vehicles) {
manager.add(vehicle);
}
manager.printAllVehicles();
}
}
这篇关于在实施工厂设计模式时如何避免“instanceof”?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!