mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-16 12:59:13 +00:00
6cd2d0353a
* update yaml frontmatter format * update abstract document * update abstract factory * use the new pattern template * acyclic visitor seo * adapter seo * ambassador seo * acl seo * aaa seo * async method invocation seo * balking seo * bridge seo * builder seo * business delegate and bytecode seo * caching seo * callback seo * chain seo * update headings * circuit breaker seo * client session + collecting parameter seo * collection pipeline seo * combinator SEO * command seo * cqrs seo * commander seo * component seo * composite seo * composite entity seo * composite view seo * context object seo * converter seo * crtp seo * currying seo * dao seo * data bus seo * data locality seo * data mapper seo * dto seo * decorator seo * delegation seo * di seo * dirty flag seo * domain model seo * double buffer seo * double checked locking seo * double dispatch seo * dynamic proxy seo * event aggregator seo * event-based asynchronous seo * eda seo * event queue seo * event sourcing seo * execute around seo * extension objects seo * facade seo * factory seo * factory kit seo * factory method seo * fanout/fanin seo * feature toggle seo * filterer seo * fluent interface seo * flux seo * flyweight seo * front controller seo * function composition seo * game loop seo * gateway seo * guarded suspension seo * half-sync/half-async seo * health check seo * hexagonal seo * identity map seo * intercepting filter seo * interpreter seo * iterator seo * layers seo * lazy loading seo * leader election seo * leader/followers seo * lockable object seo * rename and add seo for marker interface * master-worker seo * mediator seo * memento seo * metadata mapping seo * microservice aggregator seo * api gw seo * microservices log aggregration seo * mvc seo * mvi seo * mvp seo * mvvm seo * monad seo * monitor seo * monostate seo * multiton seo * mute idiom seo * naked objects & notification seo * null object seo * object mother seo * object pool seo * observer seo * optimistic locking seo * page controller seo * page object seo * parameter object seo * partial response seo * pipeline seo * poison pill seo * presentation model seo * private class data seo * producer-consumer seo * promise seo * property seo * prototype seo * proxy seo * queue-based load leveling seo * reactor seo * registry seo * repository seo * RAII seo * retry seo * role object seo * saga seo * separated interface seo * serialized entity seo * serialized lob seo * servant seo * server session seo * service layer seo * service locator seo * service to worker seo * sharding seo * single table inheritance seo * singleton seo * spatial partition seo * special case seo * specification seo * state seo * step builder seo * strangler seo * strategy seo * subclass sandbox seo * table module seo * template method seo * throttling seo * tolerant reader seo * trampoline seo * transaction script seo * twin seo * type object seo * unit of work seo * update method seo * value object seo * version number seo * virtual proxy seo * visitor seo * seo enhancements * seo improvements * SEO enhancements * SEO improvements * SEO additions * SEO improvements * more SEO improvements * rename hexagonal + SEO improvements * SEO improvements * more SEO stuff * SEO improvements * SEO optimizations * SEO enhancements * enchance SEO * improve SEO * SEO improvements * update headers
232 lines
9.2 KiB
Markdown
232 lines
9.2 KiB
Markdown
---
|
||
title: "Twin Pattern in Java: Doubling Functionality with Synchronized Twins"
|
||
shortTitle: Twin
|
||
description: "Explore the Twin design pattern in Java with examples. Learn how to implement flexible, decoupled systems without multiple inheritance for enhanced modularity and system resilience. Ideal for software developers looking to advance their coding practices."
|
||
category: Structural
|
||
language: en
|
||
tag:
|
||
- Decoupling
|
||
- Object composition
|
||
- Performance
|
||
- Resilience
|
||
---
|
||
|
||
## Intent of Twin Design Pattern
|
||
|
||
The Twin design pattern in Java provides a way to handle multiple, related classes in a manner that allows them to work together without inheriting from a common base class.
|
||
|
||
## Detailed Explanation of Twin Pattern with Real-World Examples
|
||
|
||
Real-world example
|
||
|
||
> An analogous real-world example of the Twin design pattern can be found in the relationship between a driver and a driving simulator. Imagine a driver (the first class) and a driving simulator (the second class) that both need to interact with the same set of vehicle controls (steering, acceleration, braking) and receive the same feedback (speed, engine status).
|
||
>
|
||
> Despite performing similar functions, the driver and the simulator cannot share a common base class because they operate in fundamentally different environments—one in the physical world and the other in a virtual environment. Instead, they are "twinned" to ensure consistent interaction with the vehicle controls and feedback mechanisms. This setup allows improvements or changes to be made to the simulator without affecting the driver and vice versa, maintaining the system's overall flexibility and resilience.
|
||
|
||
In plain words
|
||
|
||
> It provides a way to form two closely coupled subclasses that can act as a twin class having two ends.
|
||
|
||
Wikipedia says
|
||
|
||
> The Twin pattern is a software design pattern that allows developers to simulate multiple inheritance in languages that don't support it. Instead of creating a single class inheriting from multiple parents, two closely linked subclasses are created, each inheriting from one of the parents. These subclasses are mutually dependent, working together as a pair to achieve the desired functionality. This approach avoids the complications and inefficiencies often associated with multiple inheritance, while still allowing the reuse of functionalities from different classes.
|
||
|
||
## Programmatic Example of Twin Pattern in Java
|
||
|
||
Consider a game where a ball needs to function as both a `GameItem` and a `Thread`. Instead of inheriting from both, we use the Twin pattern with two closely linked objects: `BallItem` and `BallThread`.
|
||
|
||
Here is the `GameItem` class:
|
||
|
||
```java
|
||
@Slf4j
|
||
public abstract class GameItem {
|
||
public void draw() {
|
||
LOGGER.info("draw");
|
||
doDraw();
|
||
}
|
||
public abstract void doDraw();
|
||
public abstract void click();
|
||
}
|
||
```
|
||
|
||
`BallItem` and `BallThread` subclasses:
|
||
|
||
```java
|
||
@Slf4j
|
||
public class BallItem extends GameItem {
|
||
private boolean isSuspended;
|
||
@Setter
|
||
private BallThread twin;
|
||
|
||
@Override
|
||
public void doDraw() {
|
||
LOGGER.info("doDraw");
|
||
}
|
||
|
||
public void move() {
|
||
LOGGER.info("move");
|
||
}
|
||
|
||
@Override
|
||
public void click() {
|
||
isSuspended = !isSuspended;
|
||
if (isSuspended) {
|
||
twin.suspendMe();
|
||
} else {
|
||
twin.resumeMe();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
```java
|
||
@Slf4j
|
||
public class BallThread extends Thread {
|
||
@Setter
|
||
private BallItem twin;
|
||
private volatile boolean isSuspended;
|
||
private volatile boolean isRunning = true;
|
||
|
||
public void run() {
|
||
while (isRunning) {
|
||
if (!isSuspended) {
|
||
twin.draw();
|
||
twin.move();
|
||
}
|
||
try {
|
||
Thread.sleep(250);
|
||
} catch (InterruptedException e) {
|
||
throw new RuntimeException(e);
|
||
}
|
||
}
|
||
}
|
||
|
||
public void suspendMe() {
|
||
isSuspended = true;
|
||
LOGGER.info("Begin to suspend BallThread");
|
||
}
|
||
|
||
public void resumeMe() {
|
||
isSuspended = false;
|
||
LOGGER.info("Begin to resume BallThread");
|
||
}
|
||
|
||
public void stopMe() {
|
||
this.isRunning = false;
|
||
this.isSuspended = true;
|
||
}
|
||
}
|
||
```
|
||
|
||
To use these classes together:
|
||
|
||
```java
|
||
public class App {
|
||
|
||
public static void main(String[] args) throws Exception {
|
||
|
||
var ballItem = new BallItem();
|
||
var ballThread = new BallThread();
|
||
|
||
ballItem.setTwin(ballThread);
|
||
ballThread.setTwin(ballItem);
|
||
|
||
ballThread.start();
|
||
|
||
waiting();
|
||
|
||
ballItem.click();
|
||
|
||
waiting();
|
||
|
||
ballItem.click();
|
||
|
||
waiting();
|
||
|
||
// exit
|
||
ballThread.stopMe();
|
||
}
|
||
|
||
private static void waiting() throws Exception {
|
||
Thread.sleep(750);
|
||
}
|
||
}
|
||
```
|
||
|
||
Let's break down what happens in `App`.
|
||
|
||
1. An instance of `BallItem` and `BallThread` are created.
|
||
2. The `BallItem` and `BallThread` instances are set as twins of each other. This means that each instance has a reference to the other.
|
||
3. The `BallThread` is started. This begins the execution of the `run` method in the `BallThread` class, which continuously calls the `draw` and `move` methods of the `BallItem` (its twin) as long as the `BallThread` is not suspended.
|
||
4. The program waits for 750 milliseconds. This is done to allow the `BallThread` to execute its `run` method a few times.
|
||
5. The `click` method of the `BallItem` is called. This toggles the `isSuspended` state of the `BallItem` and its twin `BallThread`. If the `BallThread` was running, it gets suspended. If it was suspended, it resumes running.
|
||
6. Steps 4 and 5 are repeated twice. This means the `BallThread` is suspended and resumed once.
|
||
7. Finally, the `stopMe` method of the `BallThread` is called to stop its execution.
|
||
|
||
Console output:
|
||
|
||
```
|
||
14:29:33.778 [Thread-0] INFO com.iluwatar.twin.GameItem -- draw
|
||
14:29:33.780 [Thread-0] INFO com.iluwatar.twin.BallItem -- doDraw
|
||
14:29:33.780 [Thread-0] INFO com.iluwatar.twin.BallItem -- move
|
||
14:29:34.035 [Thread-0] INFO com.iluwatar.twin.GameItem -- draw
|
||
14:29:34.035 [Thread-0] INFO com.iluwatar.twin.BallItem -- doDraw
|
||
14:29:34.035 [Thread-0] INFO com.iluwatar.twin.BallItem -- move
|
||
14:29:34.291 [Thread-0] INFO com.iluwatar.twin.GameItem -- draw
|
||
14:29:34.291 [Thread-0] INFO com.iluwatar.twin.BallItem -- doDraw
|
||
14:29:34.291 [Thread-0] INFO com.iluwatar.twin.BallItem -- move
|
||
14:29:34.533 [main] INFO com.iluwatar.twin.BallThread -- Begin to suspend BallThread
|
||
14:29:35.285 [main] INFO com.iluwatar.twin.BallThread -- Begin to resume BallThread
|
||
14:29:35.308 [Thread-0] INFO com.iluwatar.twin.GameItem -- draw
|
||
14:29:35.308 [Thread-0] INFO com.iluwatar.twin.BallItem -- doDraw
|
||
14:29:35.308 [Thread-0] INFO com.iluwatar.twin.BallItem -- move
|
||
14:29:35.564 [Thread-0] INFO com.iluwatar.twin.GameItem -- draw
|
||
14:29:35.564 [Thread-0] INFO com.iluwatar.twin.BallItem -- doDraw
|
||
14:29:35.565 [Thread-0] INFO com.iluwatar.twin.BallItem -- move
|
||
14:29:35.817 [Thread-0] INFO com.iluwatar.twin.GameItem -- draw
|
||
14:29:35.817 [Thread-0] INFO com.iluwatar.twin.BallItem -- doDraw
|
||
14:29:35.817 [Thread-0] INFO com.iluwatar.twin.BallItem -- move
|
||
```
|
||
|
||
This setup allows `BallItem` and `BallThread` to act together as a single cohesive unit in the game, leveraging the capabilities of both `GameItem` and `Thread` without multiple inheritance.
|
||
|
||
## When to Use the Twin Pattern in Java
|
||
|
||
* Use when you need to decouple classes that share common functionality but cannot inherit from a common base class due to various reasons such as the use of different frameworks or languages.
|
||
* Useful in performance-critical applications where inheritance might introduce unnecessary overhead.
|
||
* Applicable in systems requiring resilience through the ability to replace or update one of the twins without affecting the other.
|
||
|
||
## Twin Pattern Java Tutorials
|
||
|
||
* [Twin – A Design Pattern for Modeling Multiple Inheritance (Hanspeter Mössenböck)](http://www.ssw.uni-linz.ac.at/Research/Papers/Moe99/Paper.pdf)
|
||
|
||
## Real-World Applications of Twin Pattern in Java
|
||
|
||
* User interfaces where different frameworks are used for rendering and logic.
|
||
* Systems integrating legacy code with new implementations where direct inheritance is not feasible.
|
||
|
||
## Benefits and Trade-offs of Twin Pattern
|
||
|
||
Benefits:
|
||
|
||
* Reduces coupling between classes, promoting modularity and easier maintenance.
|
||
* Improves flexibility and reuse of classes across different frameworks or languages.
|
||
* Enhances performance by avoiding the overhead associated with inheritance.
|
||
|
||
Trade-offs:
|
||
|
||
* Can lead to code duplication if not managed properly.
|
||
* Increased complexity in managing the interaction between twin classes.
|
||
|
||
## Related Java Design Patterns
|
||
|
||
* [Adapter](https://java-design-patterns.com/patterns/adapter/): Both patterns deal with compatibility issues, but Adapter focuses on converting interfaces while Twin deals with class collaboration without inheritance.
|
||
* [Bridge](https://java-design-patterns.com/patterns/bridge/): Similar in decoupling abstraction from implementation, but Twin specifically avoids inheritance.
|
||
* [Proxy](https://java-design-patterns.com/patterns/proxy/): Manages object access, similar to how Twin handles interaction, but Proxy typically focuses on control and logging.
|
||
|
||
## References and Credits
|
||
|
||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
|
||
* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525)
|
||
* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR)
|