implements Twin design pattern #63

This commit is contained in:
hoswey 2015-11-14 17:38:35 +08:00
parent 27199325ec
commit fdbfa9e8ee
11 changed files with 308 additions and 0 deletions

View File

@ -68,6 +68,7 @@
<module>multiton</module> <module>multiton</module>
<module>resource-acquisition-is-initialization</module> <module>resource-acquisition-is-initialization</module>
<module>thread-pool</module> <module>thread-pool</module>
<module>twin</module>
<module>private-class-data</module> <module>private-class-data</module>
<module>object-pool</module> <module>object-pool</module>
<module>dependency-injection</module> <module>dependency-injection</module>

1
twin/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target/

BIN
twin/etc/twin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

79
twin/etc/twin.ucls Normal file
View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.twin.BallThread" project="twin"
file="/twin/src/main/java/com/iluwatar/twin/BallThread.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="550" y="316"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.twin.BallItem" project="twin"
file="/twin/src/main/java/com/iluwatar/twin/BallItem.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="285" y="315"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.twin.GameItem" project="twin"
file="/twin/src/main/java/com/iluwatar/twin/GameItem.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="285" y="84"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="4" language="java" name="java.lang.Thread" project="twin"
file="/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/rt.jar" binary="true"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="550" y="96"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="false" package="false" protected="false" private="false" static="true"/>
<operations public="false" package="false" protected="false" private="false" static="true"/>
</display>
</class>
<generalization id="5">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="3"/>
</generalization>
<association id="6">
<end type="SOURCE" refId="2" navigable="false">
<attribute id="7" name="twin"/>
<multiplicity id="8" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<association id="9">
<end type="SOURCE" refId="4" navigable="false">
<attribute id="10" name="threadQ"/>
<multiplicity id="11" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="4" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<association id="12">
<end type="SOURCE" refId="1" navigable="false">
<attribute id="13" name="twin"/>
<multiplicity id="14" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="2" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<generalization id="15">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="4"/>
</generalization>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

20
twin/index.md Normal file
View File

@ -0,0 +1,20 @@
---
layout: pattern
title: Twin
folder: twin
permalink: /patterns/twin/
categories: Creational
tags: Java
---
**Intent:** Twin pattern is a design pattern which provides a standard solution to simulate multiple
inheritance in java
![alt text](./etc/twin.png "Twin")
**Applicability:** Use the Twin idiom when
* to simulate multiple inheritance in a language that does not support this feature.
* to avoid certain problems of multiple inheritance such as name clashes.

18
twin/pom.xml Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.8.0-SNAPSHOT</version>
</parent>
<artifactId>twin</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,53 @@
package com.iluwatar.twin;
/**
* Twin pattern is a design pattern which provides a standard solution to simulate multiple
* inheritance in java.
*
* <p>
* In this example, there is a ball game, a ball needs to subclass {@link GameItem} which provide
* some common method like draw and click. Moreover, it needs to subclass {@link Thread} as ball is
* a moving item (we use {@link Thread} instead of implements {@link Runnable} for example only)
* <p>
* Threre is scenario, when user click the ball, the ball will stop, when user click it gain, it
* will resume to move. We create two class, ons is {@link BallItem} which subclass {@link GameItem}
* , another is {@link BallThread} which subclass {@link Thread}. These two object both hold a field
* named "Twin" reference to another object. In {@link BallItem#click()}, it will invoke
* {@link BallThread} to suspend or resume moving; in {@link BallThread#run()}, it will invoke
* {@link BallItem} for drawing.
*
*/
public class App {
/**
* Program entry point
*
* @param args command line args
*/
public static void main(String[] args) throws Exception {
BallItem ballItem = new BallItem();
BallThread ballThread = new BallThread();
ballItem.setTwin(ballThread);
ballThread.setTwin(ballItem);
ballThread.start();
waiting();
ballItem.click();
waiting();
ballItem.click();
waiting();
ballThread.stopMe();
}
private static void waiting() throws Exception {
Thread.sleep(2500);
}
}

View File

@ -0,0 +1,41 @@
package com.iluwatar.twin;
/**
* This class represents a Ball which extends {@link GameItem} and implements the logic for ball
* item, like move and draw. It hold a reference of {@link BallThread} to delegate the suspend and
* resume task.
*/
public class BallItem extends GameItem {
private boolean isSuspended = false;
private BallThread twin;
public void setTwin(BallThread twin) {
this.twin = twin;
}
@Override
public void doDraw() {
System.out.println("doDraw");
}
public void move() {
System.out.println("move");
}
@Override
public void click() {
isSuspended = !isSuspended;
if (isSuspended) {
twin.suspendMe();
} else {
twin.resumeMe();
}
}
}

View File

@ -0,0 +1,53 @@
package com.iluwatar.twin;
/**
* This class is a UI thread for drawing the {@link BallItem}, and provide the method for suspend
* and resume. It hold the reference of {@link BallItem} to delegate the draw task.
*
*/
public class BallThread extends Thread {
private BallItem twin;
private volatile boolean isSuspended;
private volatile boolean isRunning = true;
public void setTwin(BallItem twin) {
this.twin = twin;
}
public void run() {
while (isRunning) {
while (!isSuspended) {
twin.draw();
twin.move();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public void suspendMe() {
isSuspended = true;
System.out.println("Begin to suspend BallThread");
}
public void resumeMe() {
isSuspended = false;
System.out.println("Begin to resume BallThread");
}
public void stopMe() {
this.isRunning = false;
this.isSuspended = true;
}
}

View File

@ -0,0 +1,25 @@
package com.iluwatar.twin;
/**
* GameItem is a common class which provides some common methods for game object.
*/
public abstract class GameItem {
/**
* Template method, do some common logic before draw
*
* @param other
* @return
*/
public void draw() {
System.out.println("draw");
doDraw();
}
public abstract void doDraw();
public abstract void click();
}

View File

@ -0,0 +1,17 @@
package com.iluwatar.twin;
import org.junit.Test;
/**
*
* Application test
*
*/
public class AppTest {
@Test
public void test() throws Exception {
String[] args = {};
App.main(args);
}
}