diff --git a/delegation/etc/delegation.png b/delegation/etc/delegation.png new file mode 100644 index 000000000..95219674d Binary files /dev/null and b/delegation/etc/delegation.png differ diff --git a/delegation/etc/delegation.ucls b/delegation/etc/delegation.ucls new file mode 100644 index 000000000..b55084116 --- /dev/null +++ b/delegation/etc/delegation.ucls @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/delegation/index.md b/delegation/index.md new file mode 100644 index 000000000..ad0bc6843 --- /dev/null +++ b/delegation/index.md @@ -0,0 +1,26 @@ +--- +layout: pattern +title: Delegation +folder: delegation +permalink: /patterns/delegation/ +categories: Behavioral +tags: + - Java + - Difficulty-Beginner +--- + +**Also known as:** Proxy Chains + +**Intent:** It is a technique where an object expresses certain behavior to the outside but in +reality delegates responsibility for implementing that behaviour to an associated object. + +![alt text](./etc/delegation.png "Delegate") + +**Applicability:** Use the Delegate pattern in order to achieve the following + +* Reduce the coupling of methods to their class +* Components that behave identically, but realize that this situation can change in the future. + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/delegation/pom.xml b/delegation/pom.xml new file mode 100644 index 000000000..08b7df748 --- /dev/null +++ b/delegation/pom.xml @@ -0,0 +1,51 @@ + + + + + + java-design-patterns + com.iluwatar + 1.9.0-SNAPSHOT + + 4.0.0 + + delegation + + + + junit + junit + test + + + com.github.stefanbirkner + system-rules + 1.14.0 + test + + + \ No newline at end of file diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/AbstractPrinterController.java b/delegation/src/main/java/com/iluwatar/delegation/simple/AbstractPrinterController.java new file mode 100644 index 000000000..679c1a3a6 --- /dev/null +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/AbstractPrinterController.java @@ -0,0 +1,34 @@ +package com.iluwatar.delegation.simple; + +/** + * Extra layer of abstraction for the controller to allow the controller in this example {@link PrinterController} to + * be as clean as possible. This just provides the default constructor and a simple getter method. The generic of T allows + * any implementation of {@link Printer} + * + * @param Printer + * @see Printer + * @see PrinterController + */ +public abstract class AbstractPrinterController implements Printer { + + + private T printer; + + /** + * @param printer instance of T {@link Printer} this instance is the delegate + */ + public AbstractPrinterController(T printer) { + this.printer = printer; + } + + /** + * Helper method to return the current instance of T {@link Printer} in order for + * the controller to call operations on the {@link Printer} + * + * @return instance of Printer + * @see Printer + */ + protected T getPrinter() { + return printer; + } +} diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/App.java b/delegation/src/main/java/com/iluwatar/delegation/simple/App.java new file mode 100644 index 000000000..47cf27e8e --- /dev/null +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/App.java @@ -0,0 +1,33 @@ +package com.iluwatar.delegation.simple; + +import com.iluwatar.delegation.simple.printers.CanonPrinter; +import com.iluwatar.delegation.simple.printers.EpsonPrinter; +import com.iluwatar.delegation.simple.printers.HPPrinter; + +/** + * In this example the delegates are {@link EpsonPrinter}, {@link HPPrinter} and {@link CanonPrinter} they all implement + * {@link Printer}. The {@link AbstractPrinterController} and through inheritance {@link PrinterController} also implement + * {@link Printer}. However neither provide the functionality of {@link Printer} by printing to the screen, they actually + * call upon the instance of {@link Printer} that they were instantiated with. Therefore delegating the behaviour to + * another class. + */ +public class App { + + public static final String MESSAGE_TO_PRINT = "hello world"; + + /** + * Program entry point + * + * @param args command line args + */ + public static void main(String[] args) { + AbstractPrinterController hpPrinterController = new PrinterController(new HPPrinter()); + AbstractPrinterController canonPrinterController = new PrinterController(new CanonPrinter()); + AbstractPrinterController epsonPrinterController = new PrinterController(new EpsonPrinter()); + + hpPrinterController.print(MESSAGE_TO_PRINT); + canonPrinterController.print(MESSAGE_TO_PRINT); + epsonPrinterController.print(MESSAGE_TO_PRINT); + } + +} diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/Printer.java b/delegation/src/main/java/com/iluwatar/delegation/simple/Printer.java new file mode 100644 index 000000000..aa3bebfda --- /dev/null +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/Printer.java @@ -0,0 +1,20 @@ +package com.iluwatar.delegation.simple; + +/** + * Interface that both the Controller and the Delegate will implement. + * + * @see com.iluwatar.delegation.simple.printers.CanonPrinter + * @see com.iluwatar.delegation.simple.printers.EpsonPrinter + * @see com.iluwatar.delegation.simple.printers.HPPrinter + * @see AbstractPrinterController + */ +public interface Printer { + + /** + * Method that takes a String to print to the screen. This will be implemented on both the + * controller and the delegate allowing the controller to call the same method on the delegate class. + * + * @param message to be printed to the screen + */ + void print(final String message); +} diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java b/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java new file mode 100644 index 000000000..98be53a2b --- /dev/null +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java @@ -0,0 +1,21 @@ +package com.iluwatar.delegation.simple; + +public class PrinterController extends AbstractPrinterController { + + public PrinterController(Printer printer) { + super(printer); + } + + /** + * This method is implemented from {@link Printer} however instead on providing an + * implementation, it instead calls upon the class passed through the constructor. This is the delegate, + * hence the pattern. Therefore meaning that the caller does not care of the implementing class only the owning + * controller. + * + * @param message to be printed to the screen + */ + @Override + public void print(String message) { + getPrinter().print(message); + } +} diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java new file mode 100644 index 000000000..a55e1984d --- /dev/null +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java @@ -0,0 +1,21 @@ +package com.iluwatar.delegation.simple.printers; + +import com.iluwatar.delegation.simple.Printer; + +/** + * Specialised Implementation of {@link Printer} for a Canon Printer, in + * this case the message to be printed is appended to "Canon Printer : " + * + * @see Printer + */ +public class CanonPrinter implements Printer { + + /** + * {@inheritDoc} + */ + @Override + public void print(String message) { + System.out.println("Canon Printer : " + message); + } + +} diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java new file mode 100644 index 000000000..bc53e2cae --- /dev/null +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java @@ -0,0 +1,21 @@ +package com.iluwatar.delegation.simple.printers; + +import com.iluwatar.delegation.simple.Printer; + +/** + * Specialised Implementation of {@link Printer} for a Epson Printer, in + * this case the message to be printed is appended to "Epson Printer : " + * + * @see Printer + */ +public class EpsonPrinter implements Printer{ + + /** + * {@inheritDoc} + */ + @Override + public void print(String message) { + System.out.println("Epson Printer : " + message); + } + +} diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HPPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HPPrinter.java new file mode 100644 index 000000000..e801ecdf0 --- /dev/null +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HPPrinter.java @@ -0,0 +1,21 @@ +package com.iluwatar.delegation.simple.printers; + +import com.iluwatar.delegation.simple.Printer; + +/** + * Specialised Implementation of {@link Printer} for a HP Printer, in + * this case the message to be printed is appended to "HP Printer : " + * + * @see Printer + */ +public class HPPrinter implements Printer { + + /** + * {@inheritDoc} + */ + @Override + public void print(String message) { + System.out.println("HP Printer : " + message); + } + +} diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java new file mode 100644 index 000000000..783a1a8ed --- /dev/null +++ b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java @@ -0,0 +1,13 @@ +package com.iluwatar.delegation.simple; + +import org.junit.Test; + +public class AppTest { + + @Test + public void test() { + String[] args = {}; + App.main(args); + } + +} diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java new file mode 100644 index 000000000..db8cb4262 --- /dev/null +++ b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java @@ -0,0 +1,43 @@ +package com.iluwatar.delegation.simple; + +import com.iluwatar.delegation.simple.printers.CanonPrinter; +import com.iluwatar.delegation.simple.printers.EpsonPrinter; +import com.iluwatar.delegation.simple.printers.HPPrinter; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.SystemOutRule; + +import static org.junit.Assert.assertEquals; + +public class DelegateTest { + + private static final String MESSAGE = "Test Message Printed"; + + @Rule + public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); + + @Test + public void testCanonPrinter() throws Exception { + AbstractPrinterController abstractController = new PrinterController(new CanonPrinter()); + abstractController.print(MESSAGE); + + assertEquals("Canon Printer : Test Message Printed\n", systemOutRule.getLog()); + } + + @Test + public void testHPPrinter() throws Exception { + AbstractPrinterController abstractController = new PrinterController(new HPPrinter()); + abstractController.print(MESSAGE); + + assertEquals("HP Printer : Test Message Printed\n", systemOutRule.getLog()); + } + + @Test + public void testEpsonPrinter() throws Exception { + AbstractPrinterController abstractController = new PrinterController(new EpsonPrinter()); + abstractController.print(MESSAGE); + + assertEquals("Epson Printer : Test Message Printed\n", systemOutRule.getLog()); + } + +} diff --git a/pom.xml b/pom.xml index f5f32b177..de278177e 100644 --- a/pom.xml +++ b/pom.xml @@ -88,6 +88,7 @@ reactor caching publish-subscribe + delegation