Skip to content

Commit a0abbf0

Browse files
committed
docs: update property
1 parent 6e22be3 commit a0abbf0

File tree

2 files changed

+122
-94
lines changed

2 files changed

+122
-94
lines changed

property/README.md

Lines changed: 121 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,159 @@
11
---
22
title: Property
3-
category: Creational
3+
category: Behavioral
44
language: en
55
tag:
6-
- Instantiation
6+
- Abstraction
7+
- Encapsulation
8+
- Interface
9+
- Object composition
10+
- Polymorphism
711
---
812

13+
## Also known as
14+
15+
* Dynamic Properties
16+
* Property Bag
17+
918
## Intent
10-
Create hierarchy of objects and new objects using already existing
11-
objects as parents.
19+
20+
The Property design pattern allows dynamic addition, removal, or modification of properties of an object at runtime.
1221

1322
## Explanation
1423

1524
Real-world example
1625

17-
> In the mystical land of "Elandria", adventurers can harness the power of ancient relics to customize their abilities. Each relic represents a unique property or skill. As adventurers explore, they discover and integrate new relics, dynamically enhancing their skills based on the relics they possess.
18-
19-
> Consider a modern software used in designing and customizing smartphones. Designers can choose from a variety of components such as processor type, camera specs, battery capacity, and more. Each component represents a property of the smartphone. As technology evolves and new components become available, designers can seamlessly add or replace properties to create a unique smartphone configuration without redefining the core design structure.
26+
> Imagine a custom burger ordering system at a restaurant. Each burger starts with a basic configuration (bun, patty), but customers can add or remove various ingredients (cheese, lettuce, tomato, sauces) as they wish. The restaurant's ordering system uses the Property design pattern to handle this flexibility. Each burger object dynamically updates its list of properties (ingredients) based on customer choices, allowing for a wide variety of custom burgers without needing a fixed class structure for every possible combination. This ensures the system can adapt to any new ingredient without altering the core burger class.
2027
2128
In plain words
2229

2330
> Define and manage a dynamic set of properties for an object, allowing customization without altering its structure.
2431
2532
**Programmatic Example**
26-
```java
27-
import java.util.HashMap;
28-
import java.util.Map;
2933

30-
// Enumeration for possible properties or statistics a character can have
31-
enum Stats {
32-
AGILITY, ATTACK_POWER, ARMOR, INTELLECT, SPIRIT, FURY, RAGE;
33-
}
34+
The Property design pattern, also known as Prototype inheritance, is a pattern that allows objects to be created from other objects, forming object hierarchies. This pattern is particularly useful when you want to create a new object that is a slight variation of an existing object.
3435

35-
// Enumeration for different types or classes of characters
36-
enum Type {
37-
WARRIOR, MAGE, ROGUE;
38-
}
36+
In the given code, the Property pattern is used to create different types of characters, each with their own unique properties.
3937

40-
// Interface defining prototype operations on a character
41-
interface Prototype {
42-
Integer get(Stats stat);
43-
boolean has(Stats stat);
44-
void set(Stats stat, Integer value);
45-
void remove(Stats stat);
38+
```java
39+
// The Character class represents a character in a game. It has a type and a set of properties.
40+
public class Character {
41+
private Type type;
42+
private Map<Stats, Integer> properties;
43+
44+
// The Character can be created with a type and a prototype. The new character will have the same properties as the prototype.
45+
public Character(Type type, Character prototype) {
46+
this.type = type;
47+
this.properties = new HashMap<>(prototype.properties);
48+
}
49+
50+
// Properties can be added or modified using the set method.
51+
public void set(Stats stat, int value) {
52+
properties.put(stat, value);
53+
}
54+
55+
// Properties can be removed using the remove method.
56+
public void remove(Stats stat) {
57+
properties.remove(stat);
58+
}
59+
60+
// The has method checks if a property is present.
61+
public boolean has(Stats stat) {
62+
return properties.containsKey(stat);
63+
}
64+
65+
// The get method retrieves the value of a property.
66+
public Integer get(Stats stat) {
67+
return properties.get(stat);
68+
}
4669
}
4770

48-
// Implementation of the Character class
49-
class Character implements Prototype {
50-
private String name;
51-
private Type type;
52-
private Map<Stats, Integer> properties = new HashMap<>();
53-
54-
public Character() {}
55-
56-
public Character(Type type, Prototype prototype) {
57-
this.type = type;
58-
for (Stats stat : Stats.values()) {
59-
if (prototype.has(stat)) {
60-
this.set(stat, prototype.get(stat));
61-
}
62-
}
63-
}
64-
65-
public Character(String name, Type type) {
66-
this.name = name;
67-
this.type = type;
68-
}
69-
70-
@Override
71-
public Integer get(Stats stat) {
72-
return properties.get(stat);
73-
}
74-
75-
@Override
76-
public boolean has(Stats stat) {
77-
return properties.containsKey(stat);
78-
}
79-
80-
@Override
81-
public void set(Stats stat, Integer value) {
82-
properties.put(stat, value);
83-
}
84-
85-
@Override
86-
public void remove(Stats stat) {
87-
properties.remove(stat);
88-
}
89-
90-
@Override
91-
public String toString() {
92-
return "Character{name='" + name + "', type=" + type + ", properties=" + properties + '}';
93-
}
71+
// The Stats enum represents the different properties a character can have.
72+
public enum Stats {
73+
STRENGTH, AGILITY, ARMOR, ATTACK_POWER, INTELLECT, SPIRIT, RAGE, ENERGY
9474
}
9575

96-
// Main class to demonstrate the pattern
97-
public class PropertyPatternDemo {
98-
public static void main(String[] args) {
99-
// Create a prototype character
100-
Character prototypeWarrior = new Character("Proto Warrior", Type.WARRIOR);
101-
prototypeWarrior.set(Stats.ATTACK_POWER, 10);
102-
prototypeWarrior.set(Stats.ARMOR, 15);
103-
104-
// Create a new character using the prototype
105-
Character newWarrior = new Character(Type.WARRIOR, prototypeWarrior);
106-
newWarrior.set(Stats.AGILITY, 5);
107-
108-
System.out.println(prototypeWarrior);
109-
System.out.println(newWarrior);
110-
}
76+
// The Type enum represents the different types of characters.
77+
public enum Type {
78+
MAGE, WARRIOR, ROGUE
11179
}
11280
```
11381

114-
Program output:
82+
In the main method, we create a prototype character and then create different types of characters based on the prototype:
11583

84+
```java
85+
public static void main(String[] args) {
86+
// Create a prototype character with default properties
87+
var charProto = new Character();
88+
charProto.set(Stats.STRENGTH, 10);
89+
charProto.set(Stats.AGILITY, 10);
90+
charProto.set(Stats.ARMOR, 10);
91+
charProto.set(Stats.ATTACK_POWER, 10);
92+
93+
// Create a mage character based on the prototype and add mage-specific properties
94+
var mageProto = new Character(Type.MAGE, charProto);
95+
mageProto.set(Stats.INTELLECT, 15);
96+
mageProto.set(Stats.SPIRIT, 10);
97+
98+
// Create a warrior character based on the prototype and add warrior-specific properties
99+
var warProto = new Character(Type.WARRIOR, charProto);
100+
warProto.set(Stats.RAGE, 15);
101+
warProto.set(Stats.ARMOR, 15); // boost default armor for warrior
102+
103+
// Create a rogue character based on the prototype and add rogue-specific properties
104+
var rogueProto = new Character(Type.ROGUE, charProto);
105+
rogueProto.set(Stats.ENERGY, 15);
106+
rogueProto.set(Stats.AGILITY, 15); // boost default agility for rogue
107+
108+
// Create specific characters based on the prototypes
109+
var mag = new Character("Player_1", mageProto);
110+
var warrior = new Character("Player_2", warProto);
111+
var rogue = new Character("Player_3", rogueProto);
112+
}
116113
```
117-
Character{name='Proto Warrior', type=WARRIOR, properties={ARMOR=15, ATTACK_POWER=10}}
118-
Character{name='null', type=WARRIOR, properties={ARMOR=15, AGILITY=5, ATTACK_POWER=10}}
119-
```
114+
115+
This way, we can easily create new characters with different properties without having to create a new class for each type of character.
120116

121117
## Class diagram
122-
![alt text](./etc/property.png "Property")
118+
119+
![Property](./etc/property.png "Property")
123120

124121
## Applicability
122+
125123
Use the Property pattern when
126124

127-
* When you like to have objects with dynamic set of fields and prototype inheritance
125+
* When you need to manage a flexible set of properties without altering the class structure.
126+
* When properties need to be added or removed dynamically at runtime.
127+
* When different instances of a class need different properties.
128+
129+
## Known Uses
130+
131+
* Configurations in applications where different entities require different sets of configurable parameters.
132+
* Game development where game entities (like characters or objects) need various attributes that can change during gameplay.
133+
* User profile management systems where user profiles can have dynamic attributes.
134+
135+
## Consequences
136+
137+
Benefits:
138+
139+
* Flexibility: Allows for the dynamic addition, removal, and modification of properties.
140+
* Decoupling: Reduces dependencies between classes and their properties.
141+
* Ease of Use: Simplifies the management of properties in large systems.
142+
143+
Trade-offs:
144+
145+
* Performance Overhead: Dynamic property management can introduce runtime overhead.
146+
* Complexity: May increase the complexity of the code, making it harder to maintain and understand.
147+
* Type Safety: Reduces type safety since properties are often managed as generic key-value pairs.
148+
149+
## Related Patterns
150+
151+
* [Composite](https://java-design-patterns.com/patterns/composite/): Composite allows a tree structure of objects where each node can be a complex or simple object. Property pattern can be seen as a flattened version, managing properties without hierarchy.
152+
* [Decorator](https://java-design-patterns.com/patterns/decorator/): Both patterns enhance an object's behavior, but the Property pattern focuses on adding properties dynamically, while the Decorator adds responsibilities.
153+
* [Strategy](https://java-design-patterns.com/patterns/strategy/): Like the Property pattern, the Strategy pattern allows dynamic behavior changes, but Strategy is about changing the algorithm used by an object.
128154

129-
## Real world examples
155+
## Credits
130156

131-
* [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) prototype inheritance
157+
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
158+
* [Effective Java](https://amzn.to/4cGk2Jz)
159+
* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525)

property/src/test/java/com/iluwatar/property/CharacterTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
class CharacterTest {
4242

4343
@Test
44-
void testPrototypeStats() throws Exception {
44+
void testPrototypeStats() {
4545
final var prototype = new Character();
4646

4747
for (final var stat : Stats.values()) {

0 commit comments

Comments
 (0)