issue 508 - using copy constructor to implement prototype.

As per http://www.artima.com/intv/bloch13.html, clone method in java is
broken or confusing. So staying away from clone method.
This commit is contained in:
Mahendran Mookkiah 2018-01-27 09:57:15 -05:00
parent 33a3d6fef4
commit 0805716515
14 changed files with 96 additions and 47 deletions

View File

@ -52,7 +52,7 @@ public class App {
Warlord warlord; Warlord warlord;
Beast beast; Beast beast;
factory = new HeroFactoryImpl(new ElfMage(), new ElfWarlord(), new ElfBeast()); factory = new HeroFactoryImpl(new ElfMage("cooking"), new ElfWarlord("cleaning"), new ElfBeast("protecting"));
mage = factory.createMage(); mage = factory.createMage();
warlord = factory.createWarlord(); warlord = factory.createWarlord();
beast = factory.createBeast(); beast = factory.createBeast();
@ -60,7 +60,7 @@ public class App {
LOGGER.info(warlord.toString()); LOGGER.info(warlord.toString());
LOGGER.info(beast.toString()); LOGGER.info(beast.toString());
factory = new HeroFactoryImpl(new OrcMage(), new OrcWarlord(), new OrcBeast()); factory = new HeroFactoryImpl(new OrcMage("axe"), new OrcWarlord("sword"), new OrcBeast("laser"));
mage = factory.createMage(); mage = factory.createMage();
warlord = factory.createWarlord(); warlord = factory.createWarlord();
beast = factory.createBeast(); beast = factory.createBeast();

View File

@ -30,6 +30,6 @@ package com.iluwatar.prototype;
public abstract class Beast extends Prototype { public abstract class Beast extends Prototype {
@Override @Override
public abstract Beast clone() throws CloneNotSupportedException; public abstract Beast copy() throws CloneNotSupportedException;
} }

View File

@ -28,17 +28,25 @@ package com.iluwatar.prototype;
* *
*/ */
public class ElfBeast extends Beast { public class ElfBeast extends Beast {
private String helpType;
public ElfBeast() {} public ElfBeast(String helpType) {
this.helpType = helpType;
}
public ElfBeast(ElfBeast elfBeast) {
this.helpType = elfBeast.helpType;
}
@Override @Override
public Beast clone() throws CloneNotSupportedException { public Beast copy() throws CloneNotSupportedException {
return new ElfBeast(); return new ElfBeast(this);
} }
@Override @Override
public String toString() { public String toString() {
return "Elven eagle"; return "Elven eagle helps in " + helpType;
} }
} }

View File

@ -29,16 +29,25 @@ package com.iluwatar.prototype;
*/ */
public class ElfMage extends Mage { public class ElfMage extends Mage {
public ElfMage() {}
private String helpType;
public ElfMage(String helpType) {
this.helpType = helpType;
}
public ElfMage(ElfMage elfMage) {
this.helpType = elfMage.helpType;
}
@Override @Override
public Mage clone() throws CloneNotSupportedException { public ElfMage copy() throws CloneNotSupportedException {
return new ElfMage(); return new ElfMage(this);
} }
@Override @Override
public String toString() { public String toString() {
return "Elven mage"; return "Elven mage helps in " + helpType;
} }
} }

View File

@ -29,16 +29,24 @@ package com.iluwatar.prototype;
*/ */
public class ElfWarlord extends Warlord { public class ElfWarlord extends Warlord {
public ElfWarlord() {} private String helpType;
public ElfWarlord(String helpType) {
this.helpType = helpType;
}
public ElfWarlord(ElfWarlord elfWarlord) {
this.helpType = elfWarlord.helpType;
}
@Override @Override
public Warlord clone() throws CloneNotSupportedException { public ElfWarlord copy() throws CloneNotSupportedException {
return new ElfWarlord(); return new ElfWarlord(this);
} }
@Override @Override
public String toString() { public String toString() {
return "Elven warlord"; return "Elven warlord helps in " + helpType;
} }
} }

View File

@ -47,7 +47,7 @@ public class HeroFactoryImpl implements HeroFactory {
*/ */
public Mage createMage() { public Mage createMage() {
try { try {
return mage.clone(); return mage.copy();
} catch (CloneNotSupportedException e) { } catch (CloneNotSupportedException e) {
return null; return null;
} }
@ -58,7 +58,7 @@ public class HeroFactoryImpl implements HeroFactory {
*/ */
public Warlord createWarlord() { public Warlord createWarlord() {
try { try {
return warlord.clone(); return warlord.copy();
} catch (CloneNotSupportedException e) { } catch (CloneNotSupportedException e) {
return null; return null;
} }
@ -69,7 +69,7 @@ public class HeroFactoryImpl implements HeroFactory {
*/ */
public Beast createBeast() { public Beast createBeast() {
try { try {
return beast.clone(); return beast.copy();
} catch (CloneNotSupportedException e) { } catch (CloneNotSupportedException e) {
return null; return null;
} }

View File

@ -30,6 +30,6 @@ package com.iluwatar.prototype;
public abstract class Mage extends Prototype { public abstract class Mage extends Prototype {
@Override @Override
public abstract Mage clone() throws CloneNotSupportedException; public abstract Mage copy() throws CloneNotSupportedException;
} }

View File

@ -28,17 +28,26 @@ package com.iluwatar.prototype;
* *
*/ */
public class OrcBeast extends Beast { public class OrcBeast extends Beast {
private String weapon;
public OrcBeast() {} public OrcBeast(String weapon) {
this.weapon = weapon;
}
public OrcBeast(OrcBeast orcBeast) {
this.weapon = orcBeast.weapon;
}
@Override @Override
public Beast clone() throws CloneNotSupportedException { public Beast copy() throws CloneNotSupportedException {
return new OrcBeast(); return new OrcBeast(this);
} }
@Override @Override
public String toString() { public String toString() {
return "Orcish wolf"; return "Orcish wolf attacks with " + weapon;
} }
} }

View File

@ -29,16 +29,24 @@ package com.iluwatar.prototype;
*/ */
public class OrcMage extends Mage { public class OrcMage extends Mage {
public OrcMage() {} private String weapon;
public OrcMage(String weapon) {
this.weapon = weapon;
}
public OrcMage(OrcMage orcMage) {
this.weapon = orcMage.weapon;
}
@Override @Override
public Mage clone() throws CloneNotSupportedException { public OrcMage copy() throws CloneNotSupportedException {
return new OrcMage(); return new OrcMage(this);
} }
@Override @Override
public String toString() { public String toString() {
return "Orcish mage"; return "Orcish mage attacks with " + weapon;
} }
} }

View File

@ -29,16 +29,24 @@ package com.iluwatar.prototype;
*/ */
public class OrcWarlord extends Warlord { public class OrcWarlord extends Warlord {
public OrcWarlord() {} private String weapon;
public OrcWarlord(String weapon) {
this.weapon = weapon;
}
public OrcWarlord(OrcWarlord orcWarlord) {
this.weapon = orcWarlord.weapon;
}
@Override @Override
public Warlord clone() throws CloneNotSupportedException { public OrcWarlord copy() throws CloneNotSupportedException {
return new OrcWarlord(); return new OrcWarlord(this);
} }
@Override @Override
public String toString() { public String toString() {
return "Orcish warlord"; return "Orcish warlord attacks with " + weapon;
} }
} }

View File

@ -29,7 +29,6 @@ package com.iluwatar.prototype;
*/ */
public abstract class Prototype implements Cloneable { public abstract class Prototype implements Cloneable {
@Override public abstract Object copy() throws CloneNotSupportedException;
public abstract Object clone() throws CloneNotSupportedException;
} }

View File

@ -30,6 +30,6 @@ package com.iluwatar.prototype;
public abstract class Warlord extends Prototype { public abstract class Warlord extends Prototype {
@Override @Override
public abstract Warlord clone() throws CloneNotSupportedException; public abstract Warlord copy() throws CloneNotSupportedException;
} }

View File

@ -43,18 +43,18 @@ public class HeroFactoryImplTest {
final Warlord warlord = mock(Warlord.class); final Warlord warlord = mock(Warlord.class);
final Beast beast = mock(Beast.class); final Beast beast = mock(Beast.class);
when(mage.clone()).thenThrow(CloneNotSupportedException.class); when(mage.copy()).thenThrow(CloneNotSupportedException.class);
when(warlord.clone()).thenThrow(CloneNotSupportedException.class); when(warlord.copy()).thenThrow(CloneNotSupportedException.class);
when(beast.clone()).thenThrow(CloneNotSupportedException.class); when(beast.copy()).thenThrow(CloneNotSupportedException.class);
final HeroFactoryImpl factory = new HeroFactoryImpl(mage, warlord, beast); final HeroFactoryImpl factory = new HeroFactoryImpl(mage, warlord, beast);
assertNull(factory.createMage()); assertNull(factory.createMage());
assertNull(factory.createWarlord()); assertNull(factory.createWarlord());
assertNull(factory.createBeast()); assertNull(factory.createBeast());
verify(mage).clone(); verify(mage).copy();
verify(warlord).clone(); verify(warlord).copy();
verify(beast).clone(); verify(beast).copy();
verifyNoMoreInteractions(mage, warlord, beast); verifyNoMoreInteractions(mage, warlord, beast);
} }

View File

@ -41,12 +41,12 @@ import static org.junit.jupiter.api.Assertions.assertSame;
public class PrototypeTest<P extends Prototype> { public class PrototypeTest<P extends Prototype> {
static Collection<Object[]> dataProvider() { static Collection<Object[]> dataProvider() {
return Arrays.asList( return Arrays.asList(
new Object[]{new OrcBeast(), "Orcish wolf"}, new Object[]{new OrcBeast("axe"), "Orcish wolf attacks with axe"},
new Object[]{new OrcMage(), "Orcish mage"}, new Object[]{new OrcMage("sword"), "Orcish mage attacks with sword"},
new Object[]{new OrcWarlord(), "Orcish warlord"}, new Object[]{new OrcWarlord("laser"), "Orcish warlord attacks with laser"},
new Object[]{new ElfBeast(), "Elven eagle"}, new Object[]{new ElfBeast("cooking"), "Elven eagle helps in cooking"},
new Object[]{new ElfMage(), "Elven mage"}, new Object[]{new ElfMage("cleaning"), "Elven mage helps in cleaning"},
new Object[]{new ElfWarlord(), "Elven warlord"} new Object[]{new ElfWarlord("protecting"), "Elven warlord helps in protecting"}
); );
} }
@ -55,7 +55,7 @@ public class PrototypeTest<P extends Prototype> {
public void testPrototype(P testedPrototype, String expectedToString) throws Exception { public void testPrototype(P testedPrototype, String expectedToString) throws Exception {
assertEquals(expectedToString, testedPrototype.toString()); assertEquals(expectedToString, testedPrototype.toString());
final Object clone = testedPrototype.clone(); final Object clone = testedPrototype.copy();
assertNotNull(clone); assertNotNull(clone);
assertNotSame(clone, testedPrototype); assertNotSame(clone, testedPrototype);
assertSame(testedPrototype.getClass(), clone.getClass()); assertSame(testedPrototype.getClass(), clone.getClass());