#590 Add explanation for Prototype

This commit is contained in:
Ilkka Seppälä 2017-08-16 21:09:28 +03:00
parent f6c8bfbc39
commit b639f3630e
6 changed files with 47 additions and 267 deletions

View File

@ -464,6 +464,7 @@
<param>factory-method</param>
<param>abstract-factory</param>
<param>builder</param>
<param>prototype</param>
</skipForProjects>
</configuration>
</plugin>

View File

@ -15,14 +15,57 @@ tags:
Specify the kinds of objects to create using a prototypical
instance, and create new objects by copying this prototype.
![alt text](./etc/prototype_1.png "Prototype")
## Explanation
Real world example
> Remember Dolly? The sheep that was cloned! Lets not get into the details but the key point here is that it is all about cloning.
In plain words
> Create object based on an existing object through cloning.
Wikipedia says
> The prototype pattern is a creational design pattern in software development. It is used when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects.
In short, it allows you to create a copy of an existing object and modify it to your needs, instead of going through the trouble of creating an object from scratch and setting it up.
**Programmatic Example**
In Java, it can be easily done by implementing `Cloneable` and overriding `clone` from `Object`
```
class Sheep implements Cloneable {
privage String name;
public Sheep(String name) { this.name = name; }
public void setName(String name) { this.name = name; }
public String getName() { return name; }
@Override
public Sheep clone() throws CloneNotSupportedException {
return new Sheep(name);
}
}
```
Then it can be cloned like below
```
Sheep original = new Sheep("Jolly");
System.out.println(original.getName()); // Jolly
// Clone and modify what is required
Sheep cloned = original.clone();
cloned.setName("Dolly");
System.out.println(cloned.getName()); // Dolly
```
## Applicability
Use the Prototype pattern when a system should be independent of how its products are created, composed and represented; and
* when the classes to instantiate are specified at run-time, for example, by dynamic loading; or
* to avoid building a class hierarchy of factories that parallels the class hierarchy of products; or
* when the classes to instantiate are specified at run-time, for example, by dynamic loading
* to avoid building a class hierarchy of factories that parallels the class hierarchy of products
* when instances of a class can have one of only a few different combinations of state. It may be more convenient to install a corresponding number of prototypes and clone them rather than instantiating the class manually, each time with the appropriate state
* when object creation is expensive compared to cloning
## Real world examples

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

View File

@ -1,182 +0,0 @@
<?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.prototype.ElfMage" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java" binary="false" corner="BOTTOM_RIGHT">
<position height="142" width="132" x="788" y="192"/>
<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.prototype.OrcMage" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java" binary="false" corner="BOTTOM_RIGHT">
<position height="142" width="140" x="960" y="192"/>
<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.prototype.Mage" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/Mage.java" binary="false" corner="BOTTOM_RIGHT">
<position height="105" width="132" x="665" y="28"/>
<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="com.iluwatar.prototype.Prototype" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/Prototype.java" binary="false" corner="BOTTOM_RIGHT">
<position height="105" width="132" x="493" y="-154"/>
<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="5" language="java" name="com.iluwatar.prototype.Beast" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/Beast.java" binary="false" corner="BOTTOM_RIGHT">
<position height="105" width="132" x="321" y="28"/>
<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="6" language="java" name="com.iluwatar.prototype.ElfWarlord" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java" binary="false" corner="BOTTOM_RIGHT">
<position height="142" width="154" x="388" y="192"/>
<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="7" language="java" name="com.iluwatar.prototype.Warlord" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/Warlord.java" binary="false" corner="BOTTOM_RIGHT">
<position height="105" width="132" x="493" y="28"/>
<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="8" language="java" name="com.iluwatar.prototype.ElfBeast" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java" binary="false" corner="BOTTOM_RIGHT">
<position height="142" width="132" x="32" y="192"/>
<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="9" language="java" name="com.iluwatar.prototype.OrcWarlord" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java" binary="false" corner="BOTTOM_RIGHT">
<position height="142" width="166" x="582" y="192"/>
<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="10" language="java" name="com.iluwatar.prototype.HeroFactoryImpl" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java" binary="false" corner="BOTTOM_RIGHT">
<position height="142" width="248" x="665" y="-154"/>
<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="11" language="java" name="com.iluwatar.prototype.OrcBeast" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java" binary="false" corner="BOTTOM_RIGHT">
<position height="142" width="144" x="204" y="192"/>
<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>
<interface id="12" language="java" name="com.iluwatar.prototype.HeroFactory" project="prototype"
file="/prototype/src/main/java/com/iluwatar/prototype/HeroFactory.java" binary="false" corner="BOTTOM_RIGHT">
<position height="124" width="164" x="837" y="28"/>
<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>
<generalization id="13">
<end type="SOURCE" refId="8"/>
<end type="TARGET" refId="5"/>
</generalization>
<generalization id="14">
<end type="SOURCE" refId="6"/>
<end type="TARGET" refId="7"/>
</generalization>
<generalization id="15">
<end type="SOURCE" refId="7"/>
<end type="TARGET" refId="4"/>
</generalization>
<association id="16">
<end type="SOURCE" refId="10" navigable="false">
<attribute id="17" name="beast"/>
<multiplicity id="18" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="5" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<realization id="19">
<end type="SOURCE" refId="10"/>
<end type="TARGET" refId="12"/>
</realization>
<generalization id="20">
<end type="SOURCE" refId="9"/>
<end type="TARGET" refId="7"/>
</generalization>
<generalization id="21">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="3"/>
</generalization>
<generalization id="22">
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="4"/>
</generalization>
<association id="23">
<end type="SOURCE" refId="10" navigable="false">
<attribute id="24" name="mage"/>
<multiplicity id="25" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="3" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<association id="26">
<end type="SOURCE" refId="10" navigable="false">
<attribute id="27" name="warlord"/>
<multiplicity id="28" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="7" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<generalization id="29">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="3"/>
</generalization>
<generalization id="30">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="4"/>
</generalization>
<generalization id="31">
<end type="SOURCE" refId="11"/>
<end type="TARGET" refId="5"/>
</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>

View File

@ -1,82 +0,0 @@
@startuml
package com.iluwatar.prototype {
class App {
- LOGGER : Logger {static}
+ App()
+ main(args : String[]) {static}
}
abstract class Beast {
+ Beast()
+ clone() : Beast {abstract}
}
class ElfBeast {
+ ElfBeast()
+ clone() : Beast
+ toString() : String
}
class ElfMage {
+ ElfMage()
+ clone() : Mage
+ toString() : String
}
class ElfWarlord {
+ ElfWarlord()
+ clone() : Warlord
+ toString() : String
}
interface HeroFactory {
+ createBeast() : Beast {abstract}
+ createMage() : Mage {abstract}
+ createWarlord() : Warlord {abstract}
}
class HeroFactoryImpl {
- beast : Beast
- mage : Mage
- warlord : Warlord
+ HeroFactoryImpl(mage : Mage, warlord : Warlord, beast : Beast)
+ createBeast() : Beast
+ createMage() : Mage
+ createWarlord() : Warlord
}
abstract class Mage {
+ Mage()
+ clone() : Mage {abstract}
}
class OrcBeast {
+ OrcBeast()
+ clone() : Beast
+ toString() : String
}
class OrcMage {
+ OrcMage()
+ clone() : Mage
+ toString() : String
}
class OrcWarlord {
+ OrcWarlord()
+ clone() : Warlord
+ toString() : String
}
abstract class Prototype {
+ Prototype()
+ clone() : Object {abstract}
}
abstract class Warlord {
+ Warlord()
+ clone() : Warlord {abstract}
}
}
HeroFactoryImpl --> "-beast" Beast
HeroFactoryImpl --> "-warlord" Warlord
HeroFactoryImpl --> "-mage" Mage
Beast --|> Prototype
ElfBeast --|> Beast
ElfMage --|> Mage
ElfWarlord --|> Warlord
HeroFactoryImpl ..|> HeroFactory
Mage --|> Prototype
OrcBeast --|> Beast
OrcMage --|> Mage
OrcWarlord --|> Warlord
Warlord --|> Prototype
@enduml

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB