Discovering multiple inheritance in Java with the twin pattern
This pattern allows you to combine functions of objects that tend to be used together, which is a common paradigm used by languages without multiple inheritance support.
Motivation
The twin pattern presents the possibility to implement multiple inheritance in Java. Multiple inheritance is not a supported concept as it may lead to compiler inconsistency, known as the diamond problem. The diamond problem defines a state through class abstraction where the compiler may turn out to be inconsistent. This state is due to the lack of information due to multiple abstract classes. The compiler does not have enough information about which methods should execute.
Sample code
This pattern is not supported by the platform and is rarely required for development. For these reasons, the pattern most likely does not exist inside the released JDK, as described. However, let us examine a possible example to better understand the pattern. Imagine the vehicle initiation sequence. During initiation, the engine and brake units need to be initiated together. In other words, when the engine is initiated, the brakes must be initiated too, and the other way around (Example 4.24):
public static void main(String[] args) { System.out.println("Pattern Twin, vehicle initiation sequence"); var vehicleBrakes1 = new VehicleBrakes(); var vehicleEngine1 = new VehicleEngine(); vehicleBrakes1.setEngine(vehicleEngine1); vehicleEngine1.setBrakes(vehicleBrakes1); vehicleEngine1.init(); }
Here’s the output:
Pattern Twin, vehicle initiation sequence AbstractVehiclePart, constructor AbstractVehiclePart, constructor VehicleBrakes, initiated VehicleEngine, initiated
Example 4.24 – The twin pattern gives a guarantee that both units are always initiated
The following diagram shows us tight coupling between units:
Figure 4.12 – Both considered units, VehicleEngine and VehicleBrakes, are very closely coupled
The coupling also translates into a code base that can be very fragile for future development (Example 4.25):
public class VehicleBrakes extends AbstractVehiclePart { private VehicleEngine twin; VehicleBrakes() { } void setEngine(VehicleEngine engine) { this.twin = engine; } @Override void init() { if (twin.isReady()) { setReady(); } else { setReady(); twin.init(); } System.out.println("VehicleBrakes, initiated"); } }
Example 4.25 – The VehicleBrakes class implementation shows a tight coupling with its twin, VehicleEngine
Conclusion
The twin pattern can be used to achieve multiple inheritance in Java. It must be used wisely, as a logical unwritten requirement is to guarantee complete separation of the objects under consideration. In other words, the twin design pattern allows twins to function as a single instance with extended functionality and features.