added Property pattern

This commit is contained in:
vehpsr 2015-03-29 23:03:06 +03:00
parent eddf2e630f
commit d57da2593b
10 changed files with 303 additions and 3 deletions

View File

@ -15,8 +15,9 @@ Creational design patterns abstract the instantiation process. They help make a
* [Builder](#builder) * [Builder](#builder)
* [Factory Method](#factory-method) * [Factory Method](#factory-method)
* [Prototype](#prototype) * [Prototype](#prototype)
* [Property](#property)
* [Singleton](#singleton) * [Singleton](#singleton)
### Structural Patterns ### Structural Patterns
Structural patterns are concerned with how classes and objects are composed to form larger structures. Structural patterns are concerned with how classes and objects are composed to form larger structures.
@ -433,6 +434,17 @@ Behavioral patterns are concerned with algorithms and the assignment of responsi
**Applicability:** Use the Execute Around idiom when **Applicability:** Use the Execute Around idiom when
* You use an API that requires methods to be called in pairs such as open/close or allocate/deallocate. * You use an API that requires methods to be called in pairs such as open/close or allocate/deallocate.
## <a name="property">Property</a> [&#8593;](#list-of-design-patterns)
**Intent:** Create hierarchy of objects and new objects using already existing objects as parents.
![alt text](https://github.com/iluwatar/java-design-patterns/blob/master/property/etc/property.jpg "Property")
**Applicability:** Use the Property pattern when
* when you like to have objects with dynamic set of fields and prototype inheritance
**Real world examples:**
* [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) prototype inheritance
# Frequently asked questions # Frequently asked questions
**<a id="Q1">Q: What is the difference between State and Strategy patterns?</a>** **<a id="Q1">Q: What is the difference between State and Strategy patterns?</a>**

View File

@ -41,8 +41,9 @@
<module>null-object</module> <module>null-object</module>
<module>event-aggregator</module> <module>event-aggregator</module>
<module>callback</module> <module>callback</module>
<module>execute-around</module> <module>execute-around</module>
</modules> <module>property</module>
</modules>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>

BIN
property/etc/property.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="JPEG" always-add-relationships="false"
generalizations="true" realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.Character" project="property"
file="/property/src/main/java/com/iluwatar/Character.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="497" y="232"/>
<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>
<enumeration id="2" language="java" name="com.iluwatar.Character.Type" project="property"
file="/property/src/main/java/com/iluwatar/Character.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="320" y="231"/>
<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>
</enumeration>
<enumeration id="3" language="java" name="com.iluwatar.Stats" project="property"
file="/property/src/main/java/com/iluwatar/Stats.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="695" y="205"/>
<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>
</enumeration>
<interface id="4" language="java" name="com.iluwatar.Prototype" project="property"
file="/property/src/main/java/com/iluwatar/Prototype.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="495" y="487"/>
<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>
</interface>
<association id="5">
<end type="SOURCE" refId="1" navigable="false">
<attribute id="6" name="type"/>
<multiplicity id="7" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="2" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<association id="8">
<end type="SOURCE" refId="1" navigable="false">
<attribute id="9" name="prototype"/>
<multiplicity id="10" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="4" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<nesting id="11">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="2"/>
</nesting>
<realization id="12">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="4"/>
</realization>
<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>

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

View File

@ -0,0 +1,49 @@
package com.iluwatar;
import com.iluwatar.Character.Type;
/**
* Example of Character instantiation using Property pattern (as concept also known like Prototype inheritance).
* In prototype inheritance instead of classes, as opposite to Java class inheritance,
* objects are used to create another objects and object hierarchies.
* Hierarchies are created using prototype chain through delegation: every object has link to parent object.
* Any base (parent) object can be amended at runtime (by adding or removal of some property), and all child objects will be affected as result.
*/
public class App {
public static void main(String[] args) {
/* set up */
Prototype charProto = new Character();
charProto.set(Stats.STRENGTH, 10);
charProto.set(Stats.AGILITY, 10);
charProto.set(Stats.ARMOR, 10);
charProto.set(Stats.ATTACK_POWER, 10);
Character mageProto = new Character(Type.MAGE, charProto);
mageProto.set(Stats.INTELLECT, 15);
mageProto.set(Stats.SPIRIT, 10);
Character warProto = new Character(Type.WARRIOR, charProto);
warProto.set(Stats.RAGE, 15);
warProto.set(Stats.ARMOR, 15); // boost default armor for warrior
Character rogueProto = new Character(Type.ROGUE, charProto);
rogueProto.set(Stats.ENERGY, 15);
rogueProto.set(Stats.AGILITY, 15); // boost default agility for rogue
/* usage */
Character mag = new Character("Player_1", mageProto);
mag.set(Stats.ARMOR, 8);
System.out.println(mag);
Character warrior = new Character("Player_2", warProto);
System.out.println(warrior);
Character rogue = new Character("Player_3", rogueProto);
System.out.println(rogue);
Character rogueDouble = new Character("Player_4", rogue);
rogueDouble.set(Stats.ATTACK_POWER, 12);
System.out.println(rogueDouble);
}
}

View File

@ -0,0 +1,117 @@
package com.iluwatar;
import java.util.HashMap;
import java.util.Map;
/**
* Represents Character in game and his abilities (base stats).
*/
public class Character implements Prototype {
public enum Type {
WARRIOR, MAGE, ROGUE
}
private final Prototype prototype;
private final Map<Stats, Integer> properties = new HashMap<>();
private String name;
private Type type;
public Character() {
this.prototype = new Prototype() { // Null-value object
@Override
public Integer get(Stats stat) {
return null;
}
@Override
public boolean has(Stats stat) {
return false;
}
@Override
public void set(Stats stat, Integer val) {
}
@Override
public void remove(Stats stat) {
}}
;
}
public Character(Type type, Prototype prototype) {
this.type = type;
this.prototype = prototype;
}
public Character(String name, Character prototype) {
this.name = name;
this.type = prototype.type;
this.prototype = prototype;
}
public String name() {
return name;
}
public Type type() {
return type;
}
@Override
public Integer get(Stats stat) {
boolean containsValue = properties.containsKey(stat);
if (containsValue) {
return properties.get(stat);
} else {
return prototype.get(stat);
}
}
@Override
public boolean has(Stats stat) {
return get(stat) != null;
}
@Override
public void set(Stats stat, Integer val) {
properties.put(stat, val);
}
@Override
public void remove(Stats stat) {
properties.put(stat, null);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
if (name != null) {
builder
.append("Player: ")
.append(name)
.append("\n");
}
if (type != null) {
builder
.append("Character type: ")
.append(type.name())
.append("\n");
}
builder.append("Stats:\n");
for (Stats stat : Stats.values()) {
Integer value = this.get(stat);
if (value == null) {
continue;
}
builder
.append(" - ")
.append(stat.name())
.append(":")
.append(value)
.append("\n");
}
return builder.toString();
}
}

View File

@ -0,0 +1,12 @@
package com.iluwatar;
/**
* Interface for prototype inheritance
*/
public interface Prototype {
public Integer get(Stats stat);
public boolean has(Stats stat);
public void set(Stats stat, Integer val);
public void remove(Stats stat);
}

View File

@ -0,0 +1,9 @@
package com.iluwatar;
/**
* All possible attributes that Character can have
*/
public enum Stats {
AGILITY, STRENGTH, ATTACK_POWER, ARMOR, INTELLECT, SPIRIT, ENERGY, RAGE
}

View File

@ -0,0 +1,12 @@
package com.iluwatar;
import org.junit.Test;
public class AppTest {
@Test
public void test() {
String[] args = {};
App.main(args);
}
}