Java Coding Interview Questions on decorator and composition design pattern
Q. When would you use a decorator design pattern?
A. The Decorator pattern should be used when:
- Object responsibilities and behaviors should be dynamically modifiable
- Concrete implementations should be decoupled from responsibilities and behaviors
Q. Can you write a class using the decorator design pattern to print numbers from 1-10, and then decorators that optionally print only even or odd numbers?
A. This can be done by sub classing or via inheritance. But too much sub classing is definitely a bad thing. Composition is more powerful than sub classing as you can get different behaviors via decorating at run time. Here is the code, you will realize the power of object composition and why GoF design patterns favors composition to inheritance.
Step 1: Define the interface class.
package com.arul; public interface NextNumber { abstract int getNextNumber(); }
Step 2: Define the implementation classes. The class that gets the numbers.
package com.arul; public class PrintNumbers implements NextNumber { protected int num; public PrintNumbers(int num) { this.num = num; } @Override public int getNextNumber() { return ++num; // incremented, assigned, and then returned } }
Step 3: The class that gets the odd numbers.
package com.arul; public class PrintOddNumbers implements NextNumber { protected final NextNumber next; public PrintOddNumbers(NextNumber next) { if (next instanceof PrintEvenNumbers) { throw new IllegalArgumentException("Cannot be decorated with " + PrintEvenNumbers.class); } this.next = next; } @Override public int getNextNumber() { int num = -1; if (next != null) { num = next.getNextNumber(); //keep getting the next number until it is odd while (num % 2 == 0) { num = next.getNextNumber(); } } return num; } }
Step 4: The class that gets the even numbers
package com.arul; public class PrintOddNumbers implements NextNumber { protected final NextNumber next; public PrintOddNumbers(NextNumber next) { if (next instanceof PrintEvenNumbers) { throw new IllegalArgumentException("Cannot be decorated with " + PrintEvenNumbers.class); } this.next = next; } @Override public int getNextNumber() { int num = -1; if (next != null) { num = next.getNextNumber(); //keep getting the next number until it is odd while (num % 2 == 0) { num = next.getNextNumber(); } } return num; } }
Step 5: The class that gets the multiples of 3s
package com.arul; public class PrintMultipleOfThreeNumbers implements NextNumber { protected final NextNumber next; public PrintMultipleOfThreeNumbers(NextNumber next) { this.next = next; } @Override public int getNextNumber() { int num = -1; if (next != null) { num = next.getNextNumber(); //keep getting the next number until it is odd while (num % 3 != 0) { num = next.getNextNumber(); } } return num; } }
Step 6: Finally, a sample file that shows how the above classes can be decorated at run time using object composition to get different outcomes. Additional implementations of NextNumber like PrintPrimeNumbers, PrintMultiplesOfSeven, PrintFibonacciNumber, etc can be added using the Open-Closed design principle.
package com.arul; public class TestNumbersWithDecorators { public static void main(String[] args) { //without decorators PrintNumbers pn = new PrintNumbers(0); for (int i = 0; i < 10; i++) { System.out.print(pn.getNextNumber() + " "); // print next 10 numbers } System.out.println(); PrintNumbers pn2 = new PrintNumbers(0); //print odd numbers with decorators PrintOddNumbers pOdd = new PrintOddNumbers(pn2); // decorates pn2 for (int i = 0; i < 10; i++) { System.out.print(pOdd.getNextNumber() + " "); //print next 10 odd numbers } System.out.println(); PrintNumbers pn3 = new PrintNumbers(0); //print even numbers with decorators PrintEvenNumbers pEven = new PrintEvenNumbers(pn3); // decorates pn3 for (int i = 0; i < 10; i++) { System.out.print(pEven.getNextNumber() + " "); //print next 10 even numbers } System.out.println(""); PrintNumbers pn4 = new PrintNumbers(0); //print odd numbers with decorators PrintOddNumbers pOdd2 = new PrintOddNumbers(pn4); // decorates pn4 //print multiples of 3 with decorators PrintMultipleOfThreeNumbers threes = new PrintMultipleOfThreeNumbers(pOdd2); // decorates pOdd2 for (int i = 0; i < 10; i++) { System.out.print(threes.getNextNumber() + " "); // print next 10 odd numbers // that are multiple of threes } System.out.println(""); PrintNumbers pn5 = new PrintNumbers(0); //print even numbers with decorators PrintEvenNumbers pEven2 = new PrintEvenNumbers(pn5); // decorates pn5 //print multiples of 3 with decorators PrintMultipleOfThreeNumbers threes2 = new PrintMultipleOfThreeNumbers(pEven2); // decorates pEven2 for (int i = 0; i < 10; i++) { System.out.print(threes2.getNextNumber() + " "); // print next 10 even numbers // that are multiple of threes } System.out.println(""); PrintNumbers pn6 = new PrintNumbers(0); //print multiples of 3 with decorators PrintMultipleOfThreeNumbers threes3 = new PrintMultipleOfThreeNumbers(pn6); // decorates pn6 //print even numbers with decorators PrintEvenNumbers pEven3 = new PrintEvenNumbers(threes3); // decorates threes3 for (int i = 0; i < 10; i++) { System.out.print(pEven3.getNextNumber() + " "); // print next 10 multiple of threes // that are even numbers } } }The output of running the above class is
1 2 3 4 5 6 7 8 9 10 1 3 5 7 9 11 13 15 17 19 2 4 6 8 10 12 14 16 18 20 3 9 15 21 27 33 39 45 51 57 6 12 18 24 30 36 42 48 54 60 6 12 18 24 30 36 42 48 54 60
Labels: Coding, design pattern, OO
0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home