mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-08-15 18:23:54 +00:00
This commit refactors the Prototype pattern by making it Cloneable and thus inheriting the clone() method to its subclasses which removes code duplications.
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
lombok.log.fieldName = LOGGER
|
lombok.log.fieldName = LOGGER
|
||||||
|
lombok.addLombokGeneratedAnnotation = true
|
||||||
|
|||||||
+10
-13
@@ -22,7 +22,7 @@ used for creating new objects from prototype instances.
|
|||||||
|
|
||||||
Real-world example
|
Real-world example
|
||||||
|
|
||||||
> Remember Dolly? The sheep that was cloned! Lets not get into the details but the key point here is
|
> Remember Dolly? The sheep that was cloned! Let's not get into the details but the key point here is
|
||||||
> that it is all about cloning.
|
> that it is all about cloning.
|
||||||
|
|
||||||
In plain words
|
In plain words
|
||||||
@@ -45,8 +45,11 @@ interface with a method for cloning objects. In this example, `Prototype` interf
|
|||||||
this with its `copy` method.
|
this with its `copy` method.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Prototype {
|
public abstract class Prototype<T> implements Cloneable {
|
||||||
Object copy();
|
@SneakyThrows
|
||||||
|
public T copy() {
|
||||||
|
return (T) super.clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -54,15 +57,13 @@ Our example contains a hierarchy of different creatures. For example, let's look
|
|||||||
`OrcBeast` classes.
|
`OrcBeast` classes.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public abstract class Beast implements Prototype {
|
public abstract class Beast extends Prototype<Beast> {
|
||||||
|
|
||||||
public Beast(Beast source) {
|
public Beast(Beast source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract Beast copy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@@ -76,19 +77,15 @@ public class OrcBeast extends Beast {
|
|||||||
this.weapon = orcBeast.weapon;
|
this.weapon = orcBeast.weapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public OrcBeast copy() {
|
|
||||||
return new OrcBeast(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Orcish wolf attacks with " + weapon;
|
return "Orcish wolf attacks with " + weapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We don't want to go into too much details, but the full example contains also base classes `Mage`
|
We don't want to go into too many details, but the full example contains also base classes `Mage`
|
||||||
and `Warlord` and there are specialized implementations for those for elves in addition to orcs.
|
and `Warlord` and there are specialized implementations for those for elves in addition to orcs.
|
||||||
|
|
||||||
To take full advantage of the prototype pattern, we create `HeroFactory` and `HeroFactoryImpl`
|
To take full advantage of the prototype pattern, we create `HeroFactory` and `HeroFactoryImpl`
|
||||||
|
|||||||
@@ -29,14 +29,11 @@ import lombok.NoArgsConstructor;
|
|||||||
/**
|
/**
|
||||||
* Beast.
|
* Beast.
|
||||||
*/
|
*/
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public abstract class Beast implements Prototype {
|
public abstract class Beast extends Prototype<Beast> {
|
||||||
|
|
||||||
public Beast(Beast source) {
|
public Beast(Beast source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract Beast copy();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,11 +40,6 @@ public class ElfBeast extends Beast {
|
|||||||
this.helpType = elfBeast.helpType;
|
this.helpType = elfBeast.helpType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElfBeast copy() {
|
|
||||||
return new ElfBeast(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Elven eagle helps in " + helpType;
|
return "Elven eagle helps in " + helpType;
|
||||||
|
|||||||
@@ -40,11 +40,6 @@ public class ElfMage extends Mage {
|
|||||||
this.helpType = elfMage.helpType;
|
this.helpType = elfMage.helpType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElfMage copy() {
|
|
||||||
return new ElfMage(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Elven mage helps in " + helpType;
|
return "Elven mage helps in " + helpType;
|
||||||
|
|||||||
@@ -24,31 +24,24 @@
|
|||||||
package com.iluwatar.prototype;
|
package com.iluwatar.prototype;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ElfWarlord.
|
* ElfWarlord.
|
||||||
*/
|
*/
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class ElfWarlord extends Warlord {
|
public class ElfWarlord extends Warlord {
|
||||||
|
|
||||||
private final String helpType;
|
private final String helpType;
|
||||||
|
|
||||||
public ElfWarlord(String helpType) {
|
|
||||||
this.helpType = helpType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ElfWarlord(ElfWarlord elfWarlord) {
|
public ElfWarlord(ElfWarlord elfWarlord) {
|
||||||
super(elfWarlord);
|
super(elfWarlord);
|
||||||
this.helpType = elfWarlord.helpType;
|
this.helpType = elfWarlord.helpType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElfWarlord copy() {
|
|
||||||
return new ElfWarlord(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Elven warlord helps in " + helpType;
|
return "Elven warlord helps in " + helpType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,14 +29,11 @@ import lombok.NoArgsConstructor;
|
|||||||
/**
|
/**
|
||||||
* Mage.
|
* Mage.
|
||||||
*/
|
*/
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public abstract class Mage implements Prototype {
|
public abstract class Mage extends Prototype<Mage> {
|
||||||
|
|
||||||
public Mage(Mage source) {
|
public Mage(Mage source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract Mage copy();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,11 +40,6 @@ public class OrcBeast extends Beast {
|
|||||||
this.weapon = orcBeast.weapon;
|
this.weapon = orcBeast.weapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public OrcBeast copy() {
|
|
||||||
return new OrcBeast(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Orcish wolf attacks with " + weapon;
|
return "Orcish wolf attacks with " + weapon;
|
||||||
|
|||||||
@@ -40,11 +40,6 @@ public class OrcMage extends Mage {
|
|||||||
this.weapon = orcMage.weapon;
|
this.weapon = orcMage.weapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public OrcMage copy() {
|
|
||||||
return new OrcMage(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Orcish mage attacks with " + weapon;
|
return "Orcish mage attacks with " + weapon;
|
||||||
|
|||||||
@@ -40,11 +40,6 @@ public class OrcWarlord extends Warlord {
|
|||||||
this.weapon = orcWarlord.weapon;
|
this.weapon = orcWarlord.weapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public OrcWarlord copy() {
|
|
||||||
return new OrcWarlord(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Orcish warlord attacks with " + weapon;
|
return "Orcish warlord attacks with " + weapon;
|
||||||
|
|||||||
@@ -23,11 +23,21 @@
|
|||||||
|
|
||||||
package com.iluwatar.prototype;
|
package com.iluwatar.prototype;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prototype.
|
* Prototype.
|
||||||
*/
|
*/
|
||||||
public interface Prototype {
|
@Slf4j
|
||||||
|
public abstract class Prototype<T> implements Cloneable {
|
||||||
Object copy();
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object a shallow copy of this object or null if this object is not Cloneable.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@SneakyThrows
|
||||||
|
public T copy() {
|
||||||
|
return (T) super.clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,14 +29,11 @@ import lombok.NoArgsConstructor;
|
|||||||
/**
|
/**
|
||||||
* Warlord.
|
* Warlord.
|
||||||
*/
|
*/
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public abstract class Warlord implements Prototype {
|
public abstract class Warlord extends Prototype<Warlord> {
|
||||||
|
|
||||||
public Warlord(Warlord source) {
|
public Warlord(Warlord source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract Warlord copy();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import org.junit.jupiter.params.provider.MethodSource;
|
|||||||
* @param <P> Prototype
|
* @param <P> Prototype
|
||||||
* @author Jeroen Meulemeester
|
* @author Jeroen Meulemeester
|
||||||
*/
|
*/
|
||||||
class PrototypeTest<P extends Prototype> {
|
class PrototypeTest<P extends Prototype<P>> {
|
||||||
static Collection<Object[]> dataProvider() {
|
static Collection<Object[]> dataProvider() {
|
||||||
return List.of(
|
return List.of(
|
||||||
new Object[]{new OrcBeast("axe"), "Orcish wolf attacks with axe"},
|
new Object[]{new OrcBeast("axe"), "Orcish wolf attacks with axe"},
|
||||||
|
|||||||
Reference in New Issue
Block a user