在构造函数中使用“ this”的Java双向对象引用

时间:2019-05-10 15:28:09

标签: java design-patterns bidirectional

我正在尝试创建和对象以及具有彼此双向引用的组件对象。在此示例中,我有一个Bike类和Wheel类。我考虑的一个选项(选项1)是让Bike创建Wheel,然后将其自身的引用传递给其构造函数中的Wheel。但是,我读到我不应该在构造函数之外传递“ this”,最好在Bike构造函数之外创建Wheel对象。因此,我应该先创建Wheel,然后将其传递给Bike,然后为Wheel调用setBike()方法(选项2)。在我看来,选项1是在Bike和Wheel之间创建双向参考的最简单方法,但它似乎也违反了某些设计原则。有人可以解释为什么选项2优先于选项1吗?

选项1:

public class Wheel {

    private Bike bike;

    Wheel(Bike bike) {
        this.bike = bike;
    }
}

public class Bike {

    private Wheel wheel;

    Bike() {
        this.wheel = new Wheel(this);
    }
}

Bike bike = new Bike();

选项2:

public class Wheel {

    private Bike bike;

    public void setBike(Bike bike) {
        this.bike = bike;
    }
}

public class Bike {

    private Wheel wheel;

    Bike(Wheel wheel) {
        this.wheel = wheel;
    }
}

Wheel wheel = new Wheel();
Bike bike = new Bike(wheel);
wheel.setBike(bike);

1 个答案:

答案 0 :(得分:2)

第一个选项并不像您想的那样理想。它不仅通过this,而对象没有完全初始化:this.wheel = new Wheel(this);,在这里它不会造成任何麻烦,因为这是一种非常简化的用法,而且此选项还会引起设计问题:车轮依赖关系是硬编码在构造函数中。您不能切换/模拟依赖项实例。

通常,双向关系会创建一些约束,迫使您进行一些设计权衡:两次设置值,无固定性,至少有一个暴露的设置器,因此……请注意,您可以处理一些问题。通过引入一些其他抽象来解决这些问题。

但是要简单起见,如第二个选项所示,创建两个“对象”中的至少一个是一个正确的选择。如果您可以在构造函数中处理相互关系,则可以省去setter部分的调用:

Wheel wheel = new Wheel();
Bike bike = new Bike(wheel);
// wheel.setBike(bike); // not required now

其中“自行车”的定义为:

Bike(Wheel wheel){
  this.wheel = wheel;
  wheel.setBike(this);
}

要进一步讲解,如上所述,您可以通过引入一些抽象来减少两个类之间的耦合以及关联两个实例的方式。
例如,您可以引入“自行车和车轮”界面,这是客户操纵“自行车和车轮”的唯一方法。这样,您就可以利用客户端永远不会看到的内部实现(由于private嵌套而实现了双向关系,甚至实现了某种程度的不变性。  类)。
开发API时,通常这是一种确保某些不变式和规则的方法。

想法是客户只做:

Bike bike = CarFactory.of("super bike", "hard wheel");
Wheel wheel = bike.getWheel();

接口:

public interface Wheel {
    String getBarProp();
    Bike getBike();
}

public interface Bike {
    String getFooProp();
    Wheel getWheel();
}

客户端API,而不是CarFactory中的公共实现:

public class CarFactory {

    private static class BikeDefaultImpl implements Bike {

        private final String fooProp;
        private Wheel wheel;

        public BikeDefaultImpl(String fooProp) {
            this.fooProp = fooProp;
        }

        @Override
        public String getFooProp() {
            return fooProp;
        }

        @Override
        public Wheel getWheel() {
            return wheel;
        }
    }


    private static class WheelDefaultImpl implements Wheel {

        private final String barProp;
        private Bike bike;

        public WheelDefaultImpl(String barProp) {
            this.barProp = barProp;
        }

        @Override
        public String getBarProp() {
            return barProp;
        }

        @Override
        public Bike getBike() {
            return bike;
        }
    }


    public static Bike of(String bikeProp, String wheelProp) {
        BikeDefaultImpl bike = new BikeDefaultImpl(bikeProp);
        WheelDefaultImpl wheel = new WheelDefaultImpl(wheelProp);
        bike.wheel = wheel;
        wheel.bike = bike;
        return bike;
    }

}

您还将注意到,不再需要以这种方式在构造函数中使用this,因为我们可以在内部自由访问Bike and Wheel实现的字段。