Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc8a2ef0

Browse files
noamgrinchohbus
andauthored
pattern: Active-Object pattern. (iluwatar#1660)
*Closesiluwatar#65.* Removed* Removed unnecessary files. Added logging. ClosesFixesiluwatar#1660.* Added Terminition condition.* Logger implemented. Removed maven wrapper.* Added module to parent POM. removed .gitignore* Replaced tabs with whitespaces, added Javadocs.* Fixed more whitespaces problems.* Fixed more checkstyle errors* More checkstyle errors.* Checkstyle errors.* Final checkstyle cleanup* Added UML file. Changed System.exit() to Runtime.* Changed buisiness logic and readme.md file* Changed typos and readme.md file* Fixed checkstyle errors* Fixed grammer errors and CircleCI bugs.* Wrong readme.md* Added Thread.interrupt() for after catching exception.* Fixed SonarCloud code smells.* Removed unused brackets.* Changed main program exit logic. Added tests.* Reverted abstract-factory* Cleaned code* Added static to loggers. cleaned code smells.* Checkstyle errors.* Code Smells.Co-authored-by: Subhrodip Mohanta <hello@subho.xyz>
1 parentcbf1847 commitc8a2ef0

File tree

11 files changed

+438
-10
lines changed

11 files changed

+438
-10
lines changed

‎abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,16 @@
2828
importstaticorg.junit.jupiter.api.Assertions.assertDoesNotThrow;
2929

3030
/**
31-
* Tests that Abstract Factory example runs without errors.
31+
* Issue: Add at least one assertion to this test case.
32+
*
33+
* Solution: Inserted assertion to check whether the execution of the main method in {@link App}
34+
* throws an exception.
3235
*/
3336
classAppTest {
34-
35-
/**
36-
* Issue: Add at least one assertion to this test case.
37-
*
38-
* Solution: Inserted assertion to check whether the execution of the main method in {@link App}
39-
* throws an exception.
40-
*/
41-
37+
4238
@Test
4339
voidshouldExecuteApplicationWithoutException() {
4440

45-
assertDoesNotThrow(() ->App.main(newString[]{}));
41+
assertDoesNotThrow(() ->App.main(newString[]{}));
4642
}
4743
}

‎active-object/README.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
---
2+
layout:pattern
3+
title:Active Object
4+
folder:active-object
5+
permalink:/patterns/active-object/
6+
categories:Concurrency
7+
tags:
8+
-Performance
9+
---
10+
11+
12+
##Intent
13+
The active object design pattern decouples method execution from method invocation for objects that each reside in their thread of control. The goal is to introduce concurrency, by using asynchronous method invocation and a scheduler for handling requests.
14+
15+
##Explanation
16+
17+
The class that implements the active object pattern will contain a self-synchronization mechanism without using 'synchronized' methods.
18+
19+
Real-world example
20+
21+
>The Orcs are known for their wildness and untameable soul. It seems like they have their own thread of control based on previous behavior.
22+
23+
To implement a creature that has its own thread of control mechanism and expose its API only and not the execution itself, we can use the Active Object pattern.
24+
25+
26+
**Programmatic Example**
27+
28+
```java
29+
publicabstractclassActiveCreature{
30+
privatefinalLogger logger=LoggerFactory.getLogger(ActiveCreature.class.getName());
31+
32+
privateBlockingQueue<Runnable> requests;
33+
34+
privateString name;
35+
36+
privateThread thread;
37+
38+
publicActiveCreature(Stringname) {
39+
this.name= name;
40+
this.requests=newLinkedBlockingQueue<Runnable>();
41+
thread=newThread(newRunnable() {
42+
@Override
43+
publicvoidrun() {
44+
while (true) {
45+
try {
46+
requests.take().run();
47+
}catch (InterruptedException e) {
48+
logger.error(e.getMessage());
49+
}
50+
}
51+
}
52+
}
53+
);
54+
thread.start();
55+
}
56+
57+
publicvoideat()throwsInterruptedException {
58+
requests.put(newRunnable() {
59+
@Override
60+
publicvoidrun() {
61+
logger.info("{} is eating!",name());
62+
logger.info("{} has finished eating!",name());
63+
}
64+
}
65+
);
66+
}
67+
68+
publicvoidroam()throwsInterruptedException {
69+
requests.put(newRunnable() {
70+
@Override
71+
publicvoidrun() {
72+
logger.info("{} has started to roam and the wastelands.",name());
73+
}
74+
}
75+
);
76+
}
77+
78+
publicStringname() {
79+
returnthis.name;
80+
}
81+
}
82+
83+
```
84+
85+
We can see that any class that will extend the ActiveCreature class will have its own thread of control to execute and invocate methods.
86+
87+
For example, the Orc class:
88+
```java
89+
publicclassOrcextendsActiveCreature {
90+
91+
publicOrc(Stringname) {
92+
super(name);
93+
}
94+
95+
}
96+
```
97+
98+
Now, we can create multiple creatures such as Orcs, tell them to eat and roam and they will execute it on their own thread of control:
99+
```java
100+
publicstaticvoid main(String[] args) {
101+
var app=newApp();
102+
app.run();
103+
}
104+
105+
@Override
106+
publicvoid run() {
107+
ActiveCreature creature;
108+
try {
109+
for (int i=0;i< creatures;i++) {
110+
creature=newOrc(Orc.class.getSimpleName().toString()+ i);
111+
creature.eat();
112+
creature.roam();
113+
}
114+
Thread.sleep(1000);
115+
}catch (InterruptedException e) {
116+
logger.error(e.getMessage());
117+
}
118+
Runtime.getRuntime().exit(1);
119+
}
120+
```
121+
122+
##Class diagram
123+
124+
![alt text](./etc/active-object.urm.png"Active Object class diagram")
19 KB
Loading
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
@startuml
2+
packagecom.iluwatar.activeobject {
3+
abstract classActiveCreature {
4+
-logger :Logger
5+
-name :String
6+
-requests : BlockingQueue<Runnable>
7+
-thread :Thread
8+
+ActiveCreature(name : String)
9+
+eat()
10+
+name() :String
11+
+roam()
12+
}
13+
classApp {
14+
-creatures :Integer
15+
-logger :Logger
16+
+App()
17+
+main(args : String[]) {static}
18+
+run()
19+
}
20+
classOrc {
21+
+Orc(name : String)
22+
}
23+
}
24+
Orc--|>ActiveCreature
25+
@enduml

‎active-object/pom.xml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
4+
The MIT License
5+
Copyright © 2014-2021 Ilkka Seppälä
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
25+
-->
26+
<project
27+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
28+
xmlns="http://maven.apache.org/POM/4.0.0"
29+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
30+
<modelVersion>4.0.0</modelVersion>
31+
<parent>
32+
<groupId>com.iluwatar</groupId>
33+
<artifactId>java-design-patterns</artifactId>
34+
<version>1.24.0-SNAPSHOT</version>
35+
</parent>
36+
<artifactId>active-object</artifactId>
37+
<dependencies>
38+
<dependency>
39+
<groupId>org.junit.jupiter</groupId>
40+
<artifactId>junit-jupiter-engine</artifactId>
41+
<scope>test</scope>
42+
</dependency>
43+
</dependencies>
44+
<build>
45+
<plugins>
46+
<!-- Maven assembly plugin is invoked with default setting which we have
47+
in parent pom and specifying the class having main method-->
48+
<plugin>
49+
<groupId>org.apache.maven.plugins</groupId>
50+
<artifactId>maven-assembly-plugin</artifactId>
51+
<executions>
52+
<execution>
53+
<configuration>
54+
<archive>
55+
<manifest>
56+
<mainClass>com.iluwatar.activeobject.App</mainClass>
57+
</manifest>
58+
</archive>
59+
</configuration>
60+
</execution>
61+
</executions>
62+
</plugin>
63+
</plugins>
64+
</build>
65+
</project>
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
packagecom.iluwatar.activeobject;
2+
3+
importjava.util.concurrent.BlockingQueue;
4+
importjava.util.concurrent.LinkedBlockingQueue;
5+
6+
importorg.slf4j.Logger;
7+
importorg.slf4j.LoggerFactory;
8+
9+
/**
10+
* ActiveCreature class is the base of the active object example.
11+
* @author Noam Greenshtain
12+
*
13+
*/
14+
publicabstractclassActiveCreature {
15+
16+
privatestaticfinalLoggerlogger =LoggerFactory.getLogger(ActiveCreature.class.getName());
17+
18+
privateBlockingQueue<Runnable>requests;
19+
20+
privateStringname;
21+
22+
privateThreadthread;// Thread of execution.
23+
24+
privateintstatus;// status of the thread of execution.
25+
26+
/**
27+
* Constructor and initialization.
28+
*/
29+
protectedActiveCreature(Stringname) {
30+
this.name =name;
31+
this.status =0;
32+
this.requests =newLinkedBlockingQueue<>();
33+
thread =newThread(() -> {
34+
booleaninfinite =true;
35+
while (infinite) {
36+
try {
37+
requests.take().run();
38+
}catch (InterruptedExceptione) {
39+
if (this.status !=0) {
40+
logger.error("Thread was interrupted. --> {}",e.getMessage());
41+
}
42+
infinite =false;
43+
Thread.currentThread().interrupt();
44+
}
45+
}
46+
});
47+
thread.start();
48+
}
49+
50+
/**
51+
* Eats the porridge.
52+
* @throws InterruptedException due to firing a new Runnable.
53+
*/
54+
publicvoideat()throwsInterruptedException {
55+
requests.put(() -> {
56+
logger.info("{} is eating!",name());
57+
logger.info("{} has finished eating!",name());
58+
});
59+
}
60+
61+
/**
62+
* Roam in the wastelands.
63+
* @throws InterruptedException due to firing a new Runnable.
64+
*/
65+
publicvoidroam()throwsInterruptedException {
66+
requests.put(() ->
67+
logger.info("{} has started to roam in the wastelands.",name())
68+
);
69+
}
70+
71+
/**
72+
* Returns the name of the creature.
73+
* @return the name of the creature.
74+
*/
75+
publicStringname() {
76+
returnthis.name;
77+
}
78+
79+
/**
80+
* Kills the thread of execution.
81+
* @param status of the thread of execution. 0 == OK, the rest is logging an error.
82+
*/
83+
publicvoidkill(intstatus) {
84+
this.status =status;
85+
this.thread.interrupt();
86+
}
87+
88+
/**
89+
* Returns the status of the thread of execution.
90+
* @return the status of the thread of execution.
91+
*/
92+
publicintgetStatus() {
93+
returnthis.status;
94+
}
95+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp