Twin pattern is a design pattern which provides a standard solution to simulate multiple inheritance in java
Real-world example
Consider a game with a ball that needs features of two types, Game Item, and threads to function smoothly in the game. We can use two objects, with one object compatible with the first type and the other compatible with the second type.
The pair of objects together can function as one ball in the game.
In plain words
It provides a way to form two closely coupled sub-classes that can act as a twin class having two ends.
Wikipedia says
In software engineering, the Twin pattern is a software design pattern that allows developers to model multiple inheritance in programming languages that do not support multiple inheritance. This pattern avoids many of the problems with multiple inheritance.
Programmatic Example
Take our game ball example from above. Consider we have a game in which the ball needs to be both a GameItem
and Thread
.
First of all, we have the GameItem
class given below and the Thread
class.
1
2@Slf4j
3public abstract class GameItem {
4
5 public void draw() {
6 LOGGER.info("draw");
7 doDraw();
8 }
9
10 public abstract void doDraw();
11
12
13 public abstract void click();
14}
Then, we have subclasses BallItem
and BallThread
inheriting them, respectively.
1
2@Slf4j
3public class BallItem extends GameItem {
4
5 private boolean isSuspended;
6
7 @Setter
8 private BallThread twin;
9
10 @Override
11 public void doDraw() {
12
13 LOGGER.info("doDraw");
14 }
15
16 public void move() {
17 LOGGER.info("move");
18 }
19
20 @Override
21 public void click() {
22
23 isSuspended = !isSuspended;
24
25 if (isSuspended) {
26 twin.suspendMe();
27 } else {
28 twin.resumeMe();
29 }
30 }
31}
32
33
34@Slf4j
35public class BallThread extends Thread {
36
37 @Setter
38 private BallItem twin;
39
40 private volatile boolean isSuspended;
41
42 private volatile boolean isRunning = true;
43
44 /**
45 * Run the thread.
46 */
47 public void run() {
48
49 while (isRunning) {
50 if (!isSuspended) {
51 twin.draw();
52 twin.move();
53 }
54 try {
55 Thread.sleep(250);
56 } catch (InterruptedException e) {
57 throw new RuntimeException(e);
58 }
59 }
60 }
61
62 public void suspendMe() {
63 isSuspended = true;
64 LOGGER.info("Begin to suspend BallThread");
65 }
66
67 public void resumeMe() {
68 isSuspended = false;
69 LOGGER.info("Begin to resume BallThread");
70 }
71
72 public void stopMe() {
73 this.isRunning = false;
74 this.isSuspended = true;
75 }
76}
Now, when we need the ball, we can instantiate objects from both the BallThread
and BallItem
as a pair and pass them to its pair object so they can act together as appropriate.
1
2var ballItem = new BallItem();
3var ballThread = new BallThread();
4
5ballItem.setTwin(ballThread);
6ballThread.setTwin(ballItem);
Use the Twin idiom when