实施工厂设计模式时如何避免“ instanceof”?

我正在尝试实现我的第一个工厂设计模式,但不确定将工厂制造的对象添加到列表时如何避免使用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);

        }

FFIVE
浏览 588回答 3
3回答

RISEBY

您可以实现Visitor模式。详细答案这个想法是使用多态来执行类型检查。每个子类都覆盖该accept(Visitor)方法,该方法应在超类中声明。当我们遇到如下情况时:void add(Vehicle vehicle) {&nbsp; &nbsp; //what type is vehicle??}我们可以将一个对象传递到中声明的方法中Vehicle。如果vehicle类型为Car,并class Car覆盖我们将对象传递给的方法,则该对象现在将在Car类中声明的方法内进行处理。我们利用它的优势:创建一个Visitor对象并将其传递给重写的方法:abstract class Vehicle {&nbsp; &nbsp; public abstract void accept(AddToListVisitor visitor);}class Car extends Vehicle {&nbsp; &nbsp; public void accept(AddToListVisitor visitor) {&nbsp; &nbsp; &nbsp; &nbsp; //gets handled in this class&nbsp; &nbsp; }}这Visitor应该准备好访问类型Car。您想要避免使用的任何类型instanceof都必须在中指定Visitor。class AddToListVisitor {&nbsp; &nbsp; public void visit(Car car) {&nbsp; &nbsp; &nbsp; &nbsp; //now we know the type! do something...&nbsp; &nbsp; }&nbsp; &nbsp; public void visit(Plane plane) {&nbsp; &nbsp; &nbsp; &nbsp; //now we know the type! do something...&nbsp; &nbsp; }}这是类型检查的地方!当Car接收到访问者时,它应该使用this关键字传递自己。由于我们在class中Car,因此visit(Car)将调用该方法。现在,我们知道了对象的类型,就可以在访问者内部执行所需的操作。因此,从顶部开始:您创建一个Visitor,执行所需的操作。访问者应该visit为要对其执行操作的每种对象类型提供一个方法。在这种情况下,我们正在为车辆创建访客:interface VehicleVisitor {&nbsp; &nbsp; void visit(Car car);&nbsp; &nbsp; void visit(Plane plane);&nbsp; &nbsp; void visit(Boat boat);}我们要执行的动作是将车辆添加到某物上。我们将创建一个AddTransportVisitor;负责管理交通运输的访客:class AddTransportVisitor implements VehicleVisitor {&nbsp; &nbsp; public void visit(Car car) {&nbsp; &nbsp; &nbsp; &nbsp; //add to car list&nbsp; &nbsp; }&nbsp; &nbsp; public void visit(Plane plane) {&nbsp; &nbsp; &nbsp; &nbsp; //add to plane list&nbsp; &nbsp; }&nbsp; &nbsp; public void visit(Boat boat) {&nbsp; &nbsp; &nbsp; &nbsp; //add to boat list&nbsp; &nbsp; }}每辆车都应该能够接待来访者:abstract class Vehicle {&nbsp; &nbsp; public abstract void accept(VehicleVisitor visitor);}当访客被送往车辆时,车辆应调用其visit方法,并将自身传递给参数:class Car extends Vehicle {&nbsp; &nbsp; public void accept(VehicleVisitor visitor) {&nbsp; &nbsp; &nbsp; &nbsp; visitor.visit(this);&nbsp; &nbsp; }}class Boat extends Vehicle {&nbsp; &nbsp; public void accept(VehicleVisitor visitor) {&nbsp; &nbsp; &nbsp; &nbsp; visitor.visit(this);&nbsp; &nbsp; }}class Plane extends Vehicle {&nbsp; &nbsp; public void accept(VehicleVisitor visitor) {&nbsp; &nbsp; &nbsp; &nbsp; visitor.visit(this);&nbsp; &nbsp; }}这就是类型检查的地方。visit调用了正确的方法,该方法包含根据方法的参数执行的正确代码。最后一个问题是VehicleVisitor与列表进行交互。这就是您的VehicleManager来历:它封装了列表,使您可以通过一种VehicleManager#add(Vehicle)方法添加载具。创建访问者时,我们可以将管理器传递给它(可能通过它的构造函数),这样,既然我们知道对象的类型,就可以执行所需的操作。本VehicleManager应包含的游客和拦截VehicleManager#add(Vehicle)来电:class VehicleManager {&nbsp; &nbsp; private List<Car> carList = new ArrayList<>();&nbsp; &nbsp; private List<Boat> boatList = new ArrayList<>();&nbsp; &nbsp; private List<Plane> planeList = new ArrayList<>();&nbsp; &nbsp; private AddTransportVisitor addVisitor = new AddTransportVisitor(this);&nbsp; &nbsp; public void add(Vehicle vehicle) {&nbsp; &nbsp; &nbsp; &nbsp; vehicle.accept(addVisitor);&nbsp; &nbsp; }&nbsp; &nbsp; public List<Car> getCarList() {&nbsp; &nbsp; &nbsp; &nbsp; return carList;&nbsp; &nbsp; }&nbsp; &nbsp; public List<Boat> getBoatList() {&nbsp; &nbsp; &nbsp; &nbsp; return boatList;&nbsp; &nbsp; }&nbsp; &nbsp; public List<Plane> getPlaneList() {&nbsp; &nbsp; &nbsp; &nbsp; return planeList;&nbsp; &nbsp; }}现在,我们可以为这些AddTransportVisitor#visit方法编写实现:class AddTransportVisitor implements VehicleVisitor {&nbsp; &nbsp; private VehicleManager manager;&nbsp; &nbsp; public AddTransportVisitor(VehicleManager manager) {&nbsp; &nbsp; &nbsp; &nbsp; this.manager = manager;&nbsp; &nbsp; }&nbsp; &nbsp; public void visit(Car car) {&nbsp; &nbsp; &nbsp; &nbsp; manager.getCarList().add(car);&nbsp; &nbsp; }&nbsp; &nbsp; public void visit(Plane plane) {&nbsp; &nbsp; &nbsp; &nbsp; manager.getPlaneList().add(plane);&nbsp; &nbsp; }&nbsp; &nbsp; public void visit(Boat boat) {&nbsp; &nbsp; &nbsp; &nbsp;manager.getBoatList().add(boat);&nbsp; &nbsp; }}我强烈建议删除add每种车辆的吸气剂方法并声明重载方法。这样可以减少不需要时的“访问”开销,例如manager.add(new Car()):class VehicleManager {&nbsp; &nbsp; private List<Car> carList = new ArrayList<>();&nbsp; &nbsp; private List<Boat> boatList = new ArrayList<>();&nbsp; &nbsp; private List<Plane> planeList = new ArrayList<>();&nbsp; &nbsp; private AddTransportVisitor addVisitor = new AddTransportVisitor(this);&nbsp; &nbsp; public void add(Vehicle vehicle) {&nbsp; &nbsp; &nbsp; &nbsp; vehicle.accept(addVisitor);&nbsp; &nbsp; }&nbsp; &nbsp; public void add(Car car) {&nbsp; &nbsp; &nbsp; &nbsp; carList.add(car);&nbsp; &nbsp; }&nbsp; &nbsp; public void add(Boat boat) {&nbsp; &nbsp; &nbsp; &nbsp; boatList.add(boat);&nbsp; &nbsp; }&nbsp; &nbsp; public void add(Plane plane) {&nbsp; &nbsp; &nbsp; &nbsp; planeList.add(plane);&nbsp; &nbsp; }&nbsp; &nbsp; public void printAllVehicles() {&nbsp; &nbsp; &nbsp; &nbsp; //loop through vehicles, print&nbsp; &nbsp; }}class AddTransportVisitor implements VehicleVisitor {&nbsp; &nbsp; private VehicleManager manager;&nbsp; &nbsp; public AddTransportVisitor(VehicleManager manager) {&nbsp; &nbsp; &nbsp; &nbsp; this.manager = manager;&nbsp; &nbsp; }&nbsp; &nbsp; public void visit(Car car) {&nbsp; &nbsp; &nbsp; &nbsp; manager.add(car);&nbsp; &nbsp; }&nbsp; &nbsp; public void visit(Plane plane) {&nbsp; &nbsp; &nbsp; &nbsp; manager.add(plane);&nbsp; &nbsp; }&nbsp; &nbsp; public void visit(Boat boat) {&nbsp; &nbsp; &nbsp; &nbsp;manager.add(boat);&nbsp; &nbsp; }}public class Main {&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; Vehicle[] vehicles = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Plane(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Car(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Car(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Car(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Boat(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Boat()&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; VehicleManager manager = new VehicleManager();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(Vehicle vehicle : vehicles) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; manager.add(vehicle);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; manager.printAllVehicles();&nbsp; &nbsp; }}

繁花如伊

首先,我对汽车,船只和飞机的清单不太满意。您有多个现实的例子,但清单并非一帆风顺,当您的工厂开始生产潜艇或火箭时会发生什么?取而代之的是汽车,轮船和飞机类型的枚举。您有一系列的车辆清单。通用车辆具有抽象属性CatalogAs,各种车辆实际上都实现了该属性并返回适当的值。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java