diff --git a/decorator/README.md b/decorator/README.md index 819873429..d2ba55afa 100644 --- a/decorator/README.md +++ b/decorator/README.md @@ -24,9 +24,9 @@ functionality. ## Applicability Use Decorator -* to add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects -* for responsibilities that can be withdrawn -* when extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing +* To add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects +* For responsibilities that can be withdrawn +* When extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing ## Real world examples * [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html), [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html), diff --git a/decorator/etc/decorator.png b/decorator/etc/decorator.png index 47a87b20b..35a7ef35d 100644 Binary files a/decorator/etc/decorator.png and b/decorator/etc/decorator.png differ diff --git a/decorator/etc/decorator.ucls b/decorator/etc/decorator.ucls index a5353d4ec..88bea6987 100644 --- a/decorator/etc/decorator.ucls +++ b/decorator/etc/decorator.ucls @@ -1,66 +1,72 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + + + + + + + + + - - + + - + - - - - - - - - diff --git a/decorator/src/main/java/com/iluwatar/decorator/App.java b/decorator/src/main/java/com/iluwatar/decorator/App.java index 808bd1bd7..a5225d72c 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/App.java +++ b/decorator/src/main/java/com/iluwatar/decorator/App.java @@ -32,8 +32,8 @@ import org.slf4j.LoggerFactory; * target. Using the Decorator pattern it is possible to change the behavior of the class during * runtime. *

- * In this example we show how the simple {@link Troll} first attacks and then flees the battle. - * Then we decorate the {@link Troll} with a {@link SmartHostile} and perform the attack again. You + * In this example we show how the simple {@link SimpleTroll} first attacks and then flees the battle. + * Then we decorate the {@link SimpleTroll} with a {@link ClubbedTroll} and perform the attack again. You * can see how the behavior changes after the decoration. * */ @@ -50,16 +50,16 @@ public class App { // simple troll LOGGER.info("A simple looking troll approaches."); - Hostile troll = new Troll(); + Troll troll = new SimpleTroll(); troll.attack(); troll.fleeBattle(); LOGGER.info("Simple troll power {}.\n", troll.getAttackPower()); // change the behavior of the simple troll by adding a decorator - LOGGER.info("A smart looking troll surprises you."); - Hostile smart = new SmartHostile(troll); - smart.attack(); - smart.fleeBattle(); - LOGGER.info("Smart troll power {}.\n", smart.getAttackPower()); + LOGGER.info("A troll with huge club surprises you."); + Troll clubbed = new ClubbedTroll(troll); + clubbed.attack(); + clubbed.fleeBattle(); + LOGGER.info("Clubbed troll power {}.\n", clubbed.getAttackPower()); } } diff --git a/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java b/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java new file mode 100644 index 000000000..318b76f32 --- /dev/null +++ b/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright (c) 2014 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.decorator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Decorator that adds a club for the troll + */ +public class ClubbedTroll extends TrollDecorator { + + private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class); + + public ClubbedTroll(Troll decorated) { + super(decorated); + } + + @Override + public void attack() { + super.attack(); + LOGGER.info("The troll swings at you with a club!"); + } + + @Override + public int getAttackPower() { + return super.getAttackPower() + 10; + } +} diff --git a/decorator/src/main/java/com/iluwatar/decorator/Hostile.java b/decorator/src/main/java/com/iluwatar/decorator/SimpleTroll.java similarity index 70% rename from decorator/src/main/java/com/iluwatar/decorator/Hostile.java rename to decorator/src/main/java/com/iluwatar/decorator/SimpleTroll.java index d3414c9dd..ad1316643 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/Hostile.java +++ b/decorator/src/main/java/com/iluwatar/decorator/SimpleTroll.java @@ -1,38 +1,51 @@ -/** - * The MIT License - * Copyright (c) 2014 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.decorator; - -/** - * - * Interface for the hostile enemies. - * - */ -public interface Hostile { - - void attack(); - - int getAttackPower(); - - void fleeBattle(); - -} +/** + * The MIT License + * Copyright (c) 2014 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.decorator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * SimpleTroll implements {@link Troll} interface directly. + * + */ +public class SimpleTroll implements Troll { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleTroll.class); + + @Override + public void attack() { + LOGGER.info("The troll tries to grab you!"); + } + + @Override + public int getAttackPower() { + return 10; + } + + @Override + public void fleeBattle() { + LOGGER.info("The troll shrieks in horror and runs away!"); + } +} diff --git a/decorator/src/main/java/com/iluwatar/decorator/Troll.java b/decorator/src/main/java/com/iluwatar/decorator/Troll.java index 0fff3b812..d9f1da968 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/Troll.java +++ b/decorator/src/main/java/com/iluwatar/decorator/Troll.java @@ -1,51 +1,38 @@ -/** - * The MIT License - * Copyright (c) 2014 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.decorator; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * Troll implements {@link Hostile} interface directly. - * - */ -public class Troll implements Hostile { - - private static final Logger LOGGER = LoggerFactory.getLogger(Troll.class); - - @Override - public void attack() { - LOGGER.info("The troll swings at you with a club!"); - } - - @Override - public int getAttackPower() { - return 10; - } - - @Override - public void fleeBattle() { - LOGGER.info("The troll shrieks in horror and runs away!"); - } -} +/** + * The MIT License + * Copyright (c) 2014 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.decorator; + +/** + * + * Interface for trolls + * + */ +public interface Troll { + + void attack(); + + int getAttackPower(); + + void fleeBattle(); + +} diff --git a/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java b/decorator/src/main/java/com/iluwatar/decorator/TrollDecorator.java similarity index 71% rename from decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java rename to decorator/src/main/java/com/iluwatar/decorator/TrollDecorator.java index 9a4a136ad..4495311cf 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java +++ b/decorator/src/main/java/com/iluwatar/decorator/TrollDecorator.java @@ -22,40 +22,32 @@ */ package com.iluwatar.decorator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** - * SmartHostile is a decorator for {@link Hostile} objects. The calls to the {@link Hostile} interface - * are intercepted and decorated. Finally the calls are delegated to the decorated {@link Hostile} + * TrollDecorator is a decorator for {@link Troll} objects. The calls to the {@link Troll} interface + * are intercepted and decorated. Finally the calls are delegated to the decorated {@link Troll} * object. * */ -public class SmartHostile implements Hostile { +public class TrollDecorator implements Troll { - private static final Logger LOGGER = LoggerFactory.getLogger(SmartHostile.class); + private Troll decorated; - private Hostile decorated; - - public SmartHostile(Hostile decorated) { + public TrollDecorator(Troll decorated) { this.decorated = decorated; } @Override public void attack() { - LOGGER.info("It throws a rock at you!"); decorated.attack(); } @Override public int getAttackPower() { - // decorated hostile's power + 20 because it is smart - return decorated.getAttackPower() + 20; + return decorated.getAttackPower(); } @Override public void fleeBattle() { - LOGGER.info("It calls for help!"); decorated.fleeBattle(); } } diff --git a/decorator/src/test/java/com/iluwatar/decorator/SmartHostileTest.java b/decorator/src/test/java/com/iluwatar/decorator/ClubbedTrollTest.java similarity index 79% rename from decorator/src/test/java/com/iluwatar/decorator/SmartHostileTest.java rename to decorator/src/test/java/com/iluwatar/decorator/ClubbedTrollTest.java index 6432d4e90..75b98df1a 100644 --- a/decorator/src/test/java/com/iluwatar/decorator/SmartHostileTest.java +++ b/decorator/src/test/java/com/iluwatar/decorator/ClubbedTrollTest.java @@ -29,30 +29,26 @@ import static org.mockito.Mockito.*; import static org.mockito.internal.verification.VerificationModeFactory.times; /** - * Date: 12/7/15 - 7:47 PM - * - * @author Jeroen Meulemeester + * Tests for {@link ClubbedTroll} */ -public class SmartHostileTest { +public class ClubbedTrollTest { @Test public void testSmartHostile() throws Exception { // Create a normal troll first, but make sure we can spy on it later on. - final Hostile simpleTroll = spy(new Troll()); + final Troll simpleTroll = spy(new SimpleTroll()); - // Now we want to decorate the troll to make it smarter ... - final Hostile smartTroll = new SmartHostile(simpleTroll); - assertEquals(30, smartTroll.getAttackPower()); + // Now we want to decorate the troll to make it stronger ... + final Troll clubbed = new ClubbedTroll(simpleTroll); + assertEquals(20, clubbed.getAttackPower()); verify(simpleTroll, times(1)).getAttackPower(); - // Check if the smart troll actions are delegated to the decorated troll - smartTroll.attack(); + // Check if the clubbed troll actions are delegated to the decorated troll + clubbed.attack(); verify(simpleTroll, times(1)).attack(); - smartTroll.fleeBattle(); + clubbed.fleeBattle(); verify(simpleTroll, times(1)).fleeBattle(); verifyNoMoreInteractions(simpleTroll); - } - } diff --git a/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java b/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java similarity index 90% rename from decorator/src/test/java/com/iluwatar/decorator/TrollTest.java rename to decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java index 652c1fcdc..775813eff 100644 --- a/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java +++ b/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java @@ -36,17 +36,15 @@ import java.util.List; import static org.junit.Assert.assertEquals; /** - * Date: 12/7/15 - 7:26 PM - * - * @author Jeroen Meulemeester + * Tests for {@link SimpleTroll} */ -public class TrollTest { +public class SimpleTrollTest { private InMemoryAppender appender; @Before public void setUp() { - appender = new InMemoryAppender(Troll.class); + appender = new InMemoryAppender(SimpleTroll.class); } @After @@ -56,11 +54,11 @@ public class TrollTest { @Test public void testTrollActions() throws Exception { - final Troll troll = new Troll(); + final SimpleTroll troll = new SimpleTroll(); assertEquals(10, troll.getAttackPower()); troll.attack(); - assertEquals("The troll swings at you with a club!", appender.getLastMessage()); + assertEquals("The troll tries to grab you!", appender.getLastMessage()); troll.fleeBattle(); assertEquals("The troll shrieks in horror and runs away!", appender.getLastMessage());