Merge pull request #258 from amit2103/master

MonoState Pattern
This commit is contained in:
Ilkka Seppälä 2015-10-13 20:03:45 +03:00
commit 3c8b83748a
10 changed files with 261 additions and 2 deletions

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.monostate.LoadBalancer" project="monostate"
file="/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java" binary="false" corner="BOTTOM_RIGHT">
<position height="187" width="158" x="100" y="66"/>
<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.monostate.Server" project="monostate"
file="/monostate/src/main/java/com/iluwatar/monostate/Server.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="176" y="372"/>
<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.monostate.Request" project="monostate"
file="/monostate/src/main/java/com/iluwatar/monostate/Request.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="329" y="352"/>
<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>
<dependency id="4">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="3"/>
</dependency>
<dependency id="5">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="3"/>
</dependency>
<association id="6">
<end type="SOURCE" refId="1" navigable="false">
<attribute id="7" name="servers"/>
<multiplicity id="8" minimum="0" maximum="2147483647"/>
</end>
<end type="TARGET" refId="2" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<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>

BIN
monostate/etc/monostate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

28
monostate/index.md Normal file
View File

@ -0,0 +1,28 @@
---
layout: pattern
title: MonoState
folder: monostate
permalink: /patterns/monostate/
categories: Creational
tags: Java
---
**Intent:** Enforces a behaviour like sharing the same state amongst all instances.
![alt text](./etc/monostate.png "MonoState")
**Applicability:** Use the Monostate pattern when
* The same state must be shared across all instances of a class.
* Typically this pattern might be used everywhere a Singleton might be used. Singleton usage however is not transparent, Monostate usage is.
* Monostate has one major advantage over singleton. The subclasses might decorate the shared state as they wish and hence can provide dynamically different behaviour than the base class.
**Typical Use Case:**
* the logging class
* managing a connection to a database
* file manager
**Real world examples:**
Yet to see this.

18
monostate/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.7.0</version>
</parent>
<artifactId>monostate</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,35 @@
package com.iluwatar.monostate;
/**
*
* The MonoState pattern ensures that all instances of the class will have the same state. This can
* be used a direct replacement of the Singleton pattern.
*
* <p>
* In the following example, The {@link LoadBalancer} class represents the app's logic. It contains
* a series of Servers, which can handle requests of type {@link Request}. Two instances of
* LoadBalacer are created. When a request is made to a server via the first LoadBalancer the state
* change in the first load balancer affects the second. So if the first LoadBalancer selects the
* Server 1, the second LoadBalancer on a new request will select the Second server. If a third
* LoadBalancer is created and a new request is made to it, then it will select the third server as
* the second load balancer has already selected the second server.
* <p>
* .
*
*/
public class App {
/**
* Program entry point
*
* @param args command line args
*/
public static void main(String[] args) {
LoadBalancer loadBalancer1 = new LoadBalancer();
LoadBalancer loadBalancer2 = new LoadBalancer();
loadBalancer1.serverequest(new Request("Hello"));
loadBalancer2.serverequest(new Request("Hello World"));
}
}

View File

@ -0,0 +1,52 @@
package com.iluwatar.monostate;
import java.util.ArrayList;
import java.util.List;
/**
* The LoadBalancer class. This implements the MonoState pattern. It holds a series of servers. Upon
* receiving a new Request, it delegates the call to the servers in a Round Robin Fashion. Since all
* instances of the class share the same state, all instances will delegate to the same server on
* receiving a new Request.
*
*/
public class LoadBalancer {
private static List<Server> servers = new ArrayList<>();
private static int id = 0;
private static int lastServedId = 0;
static {
servers.add(new Server("localhost", 8081, ++id));
servers.add(new Server("localhost", 8080, ++id));
servers.add(new Server("localhost", 8082, ++id));
servers.add(new Server("localhost", 8083, ++id));
servers.add(new Server("localhost", 8084, ++id));
}
public final void addServer(Server server) {
synchronized (servers) {
servers.add(server);
}
}
public final int getNoOfServers() {
return servers.size();
}
public static int getLastServedId() {
return lastServedId;
}
public void serverequest(Request request) {
if (lastServedId >= servers.size()) {
lastServedId = 0;
}
Server server = servers.get(lastServedId++);
server.serve(request);
}
}

View File

@ -0,0 +1,15 @@
package com.iluwatar.monostate;
/**
*
* The Request class. A {@link Server} can handle an instance of a Request.
*
*/
public class Request {
public final String value;
public Request(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,31 @@
package com.iluwatar.monostate;
/**
*
* The Server class. Each Server sits behind a LoadBalancer which delegates the call to the
* servers in a simplistic Round Robin fashion.
*
*/
public class Server {
public final String host;
public final int port;
public final int id;
public Server(String host, int port, int id) {
this.host = host;
this.port = port;
this.id = id;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public final void serve(Request request) {
System.out.println("Server ID " + id + " associated to host : " + getHost() + " and Port " + getPort() +" Processed request with value " + request.value);
}
}

View File

@ -0,0 +1,26 @@
package com.iluwatar.monostate;
import org.junit.Assert;
import org.junit.Test;
public class AppTest {
@Test
public void testSameStateAmonstAllInstances() {
LoadBalancer balancer = new LoadBalancer();
LoadBalancer balancer2 = new LoadBalancer();
balancer.addServer(new Server("localhost", 8085, 6));
// Both should have the same number of servers.
Assert.assertTrue(balancer.getNoOfServers() == balancer2.getNoOfServers());
// Both Should have the same LastServedId
Assert.assertTrue(balancer.getLastServedId() == balancer2.getLastServedId());
}
@Test
public void testMain() {
String[] args = {};
App.main(args);
Assert.assertTrue(LoadBalancer.getLastServedId() == 2);
}
}

View File

@ -73,9 +73,10 @@
<module>front-controller</module>
<module>repository</module>
<module>async-method-invocation</module>
<module>business-delegate</module>
<module>half-sync-half-async</module>
<module>monostate</module>
<module>step-builder</module>
<module>business-delegate</module>
<module>half-sync-half-async</module>
<module>layers</module>
<module>message-channel</module>
<module>fluentinterface</module>