BAEL-1072 - Difference between Proxy, Decorator, Adapter, and Bridge Patterns (#2390)

* Structural Design Patterns 

Difference between several types of structural design patterns

* Structural Design Pattern

Difference between several types of structural design patterns

* Structural Design Patterns

Difference between several types of structural design patterns

* Structural Design Patterns

Difference between several types of structural design patterns
This commit is contained in:
ramansahasi 2017-08-08 23:26:53 +05:30 committed by maibin
parent 53433a06d8
commit 415b80d03f
29 changed files with 498 additions and 1 deletions

View File

@ -80,7 +80,11 @@
</dependency>
<!-- logging -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>

View File

@ -0,0 +1,13 @@
package com.baeldung.designpatterns.adapter;
import static com.baeldung.designpatterns.util.LogerUtil.LOG;
public class AdapterPatternDriver {
public static void main(String args[]) {
LuxuryCarsSpeedAdapter luxuryCars = new LuxuryCarsSpeedAdapterImpl();
LOG.info("Bugatti Veyron Super Sport's top speed is " + luxuryCars.bugattiVeyronInKMPH() + " Kmph.");
LOG.info("McLaren F1 top speed is " + luxuryCars.mcLarenInKMPH() + " Kmph.");
LOG.info("Aston Martin One-77 top speed is " + luxuryCars.astonMartinInKMPH() + " Kmph.");
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung.designpatterns.adapter;
public class LuxuryCarsSpeed {
public double bugattiVeyronInMPH() {
return 268;
}
public double mcLarenInMPH() {
return 241;
}
public double astonMartinInMPH() {
return 220;
}
}

View File

@ -0,0 +1,7 @@
package com.baeldung.designpatterns.adapter;
public interface LuxuryCarsSpeedAdapter {
public double bugattiVeyronInKMPH();
public double mcLarenInKMPH();
public double astonMartinInKMPH();
}

View File

@ -0,0 +1,26 @@
package com.baeldung.designpatterns.adapter;
public class LuxuryCarsSpeedAdapterImpl extends LuxuryCarsSpeed implements LuxuryCarsSpeedAdapter {
@Override
public double bugattiVeyronInKMPH() {
double mph = super.bugattiVeyronInMPH();
return convertMPHtoKMPH(mph);
}
@Override
public double mcLarenInKMPH() {
double mph = super.mcLarenInMPH();
return convertMPHtoKMPH(mph);
}
@Override
public double astonMartinInKMPH() {
double mph = super.astonMartinInMPH();
return convertMPHtoKMPH(mph);
}
private double convertMPHtoKMPH(double mph) {
return mph * 1.60934;
}
}

View File

@ -0,0 +1,12 @@
package com.baeldung.designpatterns.bridge;
import static com.baeldung.designpatterns.util.LogerUtil.LOG;
public class Blue implements Color {
@Override
public void fillColor() {
LOG.info("Color : Blue");
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.designpatterns.bridge;
public class BridgePatternDriver {
public static void main(String[] args) {
//a square with red color
Shape square = new Square(new Red());
square.drawShape();
//a triangle with blue color
Shape triangle = new Triangle(new Blue());
triangle.drawShape();
}
}

View File

@ -0,0 +1,5 @@
package com.baeldung.designpatterns.bridge;
public interface Color {
public void fillColor();
}

View File

@ -0,0 +1,12 @@
package com.baeldung.designpatterns.bridge;
import static com.baeldung.designpatterns.util.LogerUtil.LOG;
public class Red implements Color {
@Override
public void fillColor() {
LOG.info("Color : Red");
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.designpatterns.bridge;
public abstract class Shape {
protected Color color;
public Shape(Color color) {
this.color = color;
}
abstract public void drawShape();
}

View File

@ -0,0 +1,16 @@
package com.baeldung.designpatterns.bridge;
import static com.baeldung.designpatterns.util.LogerUtil.LOG;
public class Square extends Shape {
public Square(Color color) {
super(color);
}
@Override
public void drawShape() {
LOG.info("Square drawn. ");
color.fillColor();
}
}

View File

@ -0,0 +1,16 @@
package com.baeldung.designpatterns.bridge;
import static com.baeldung.designpatterns.util.LogerUtil.LOG;
public class Triangle extends Shape {
public Triangle(Color color) {
super(color);
}
@Override
public void drawShape() {
LOG.info("Triangle drawn. ");
color.fillColor();
}
}

View File

@ -0,0 +1,16 @@
package com.baeldung.designpatterns.decorator;
public class BubbleLights extends TreeDecorator {
public BubbleLights(ChristmasTree tree) {
super(tree);
}
public String decorate() {
return super.decorate() + decorateWithBubbleLights();
}
private String decorateWithBubbleLights() {
return " with Bubble Lights";
}
}

View File

@ -0,0 +1,5 @@
package com.baeldung.designpatterns.decorator;
public interface ChristmasTree {
public String decorate();
}

View File

@ -0,0 +1,10 @@
package com.baeldung.designpatterns.decorator;
public class ChristmasTreeImpl implements ChristmasTree {
@Override
public String decorate() {
return "Christmas tree";
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.designpatterns.decorator;
import static com.baeldung.designpatterns.util.LogerUtil.LOG;
public class DecoratorPatternDriver {
public static void main(String[] args) {
//christmas tree with just one Garland
ChristmasTree tree1 = new Garland(new ChristmasTreeImpl());
LOG.info(tree1.decorate());
//christmas tree with two Garlands and one Bubble lights
ChristmasTree tree2 = new BubbleLights(new Garland(
new Garland(new ChristmasTreeImpl()))
);
LOG.info(tree2.decorate());
}
}

View File

@ -0,0 +1,16 @@
package com.baeldung.designpatterns.decorator;
public class Garland extends TreeDecorator {
public Garland(ChristmasTree tree) {
super(tree);
}
public String decorate() {
return super.decorate() + decorateWithGarland();
}
private String decorateWithGarland() {
return " with Garland";
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung.designpatterns.decorator;
public abstract class TreeDecorator implements ChristmasTree {
private ChristmasTree tree;
public TreeDecorator(ChristmasTree tree) {
this.tree = tree;
}
@Override
public String decorate() {
return tree.decorate();
}
}

View File

@ -0,0 +1,5 @@
package com.baeldung.designpatterns.proxy;
public interface ExpensiveObject {
public void process();
}

View File

@ -0,0 +1,20 @@
package com.baeldung.designpatterns.proxy;
import static com.baeldung.designpatterns.util.LogerUtil.LOG;;
public class ExpensiveObjectImpl implements ExpensiveObject {
public ExpensiveObjectImpl() {
heavyInitialConfiguration();
}
@Override
public void process() {
LOG.info("processing complete.");
}
private void heavyInitialConfiguration() {
LOG.info("Loading initial configuration...");
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.designpatterns.proxy;
public class ExpensiveObjectProxy implements ExpensiveObject{
private static ExpensiveObject object;
@Override
public void process() {
if(object == null) {
object = new ExpensiveObjectImpl();
}
object.process();
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.designpatterns.proxy;
public class ProxyPatternDriver {
public static void main(String[] args) {
ExpensiveObject object = new ExpensiveObjectProxy();
object.process();
object.process();
}
}

View File

@ -0,0 +1,35 @@
package com.baeldung.designpatterns.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public class LogerUtil {
public final static Logger LOG = Logger.getLogger("GLOBAL");
static {
configuration();
}
private static void configuration() {
Properties props = new Properties();
try {
props.load(
new BufferedReader(
new InputStreamReader(
LogerUtil.class.getResourceAsStream("/log4jstructuraldp.properties")
)
)
);
} catch (IOException e) {
System.out.println("log4jstructuraldp.properties file not configured properly");
System.exit(0);
}
PropertyConfigurator.configure(props);
}
}

View File

@ -0,0 +1,9 @@
# Root logger
log4j.rootLogger=INFO, file, stdout
# Write to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

View File

@ -0,0 +1,20 @@
package com.baeldung.designpatterns;
import static org.junit.Assert.*;
import org.junit.Test;
import com.baeldung.designpatterns.adapter.LuxuryCarsSpeedAdapter;
import com.baeldung.designpatterns.adapter.LuxuryCarsSpeedAdapterImpl;
public class AdapterPatternIntegrationTest {
@Test
public void givenLuxuryCarsAdapter_WhenConvertingMPHToKMPH_thenSuccessfullyConverted() {
LuxuryCarsSpeedAdapter luxuryCars = new LuxuryCarsSpeedAdapterImpl();
assertEquals(luxuryCars.bugattiVeyronInKMPH(), 431.30312, 0.00001);
assertEquals(luxuryCars.mcLarenInKMPH(), 387.85094, 0.00001);
assertEquals(luxuryCars.astonMartinInKMPH(), 354.0548, 0.00001);
}
}

View File

@ -0,0 +1,52 @@
package com.baeldung.designpatterns;
import static com.baeldung.designpatterns.util.LogerUtil.LOG;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.util.List;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.designpatterns.bridge.Blue;
import com.baeldung.designpatterns.bridge.Red;
import com.baeldung.designpatterns.bridge.Shape;
import com.baeldung.designpatterns.bridge.Square;
import com.baeldung.designpatterns.bridge.Triangle;
public class BridgePatternIntegrationTest {
public static TestAppenderDP appender;
@Before
public void setUp() {
appender = new TestAppenderDP();
LOG.addAppender(appender);
}
@Test
public void whenBridgePatternInvoked_thenConfigSuccess() {
//a square with red color
Shape square = new Square(new Red());
square.drawShape();
//a triangle with blue color
Shape triangle = new Triangle(new Blue());
triangle.drawShape();
final List<LoggingEvent> log = appender.getLog();
assertThat((String) log.get(0).getMessage(), is("Square drawn. "));
assertThat((String) log.get(1).getMessage(), is("Color : Red"));
assertThat((String) log.get(2).getMessage(), is("Triangle drawn. "));
assertThat((String) log.get(3).getMessage(), is("Color : Blue"));
}
@After
public void tearDown() {
LOG.removeAppender(appender);
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.designpatterns;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.baeldung.designpatterns.decorator.BubbleLights;
import com.baeldung.designpatterns.decorator.ChristmasTree;
import com.baeldung.designpatterns.decorator.ChristmasTreeImpl;
import com.baeldung.designpatterns.decorator.Garland;
public class DecoratorPatternIntegrationTest {
private ChristmasTree tree;
@Test
public void givenDecoratorPattern_WhenDecoratorsInjectedAtRuntime_thenConfigSuccess() {
//christmas tree with just one Garland
tree = new Garland(new ChristmasTreeImpl());
assertEquals(tree.decorate(), "Christmas tree with Garland");
//christmas tree with two Garlands and one Bubble lights
tree = new BubbleLights(new Garland(
new Garland(new ChristmasTreeImpl()))
);
assertEquals(tree.decorate(), "Christmas tree with Garland with Garland with Bubble Lights");
}
}

View File

@ -0,0 +1,44 @@
package com.baeldung.designpatterns;
import static com.baeldung.designpatterns.util.LogerUtil.LOG;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.util.List;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.designpatterns.proxy.ExpensiveObject;
import com.baeldung.designpatterns.proxy.ExpensiveObjectProxy;
public class ProxyPatternIntegrationTest {
public static TestAppenderDP appender;
@Before
public void setUp() {
appender = new TestAppenderDP();
LOG.addAppender(appender);
}
@Test
public void givenExpensiveObjectProxy_WhenObjectInitialized_thenInitializedOnlyOnce() {
ExpensiveObject object = new ExpensiveObjectProxy();
object.process();
object.process();
final List<LoggingEvent> log = appender.getLog();
assertThat((String) log.get(0).getMessage(), is("Loading initial configuration..."));
assertThat((String) log.get(1).getMessage(), is("processing complete."));
assertThat((String) log.get(2).getMessage(), is("processing complete."));
}
@After
public void tearDown() {
LOG.removeAppender(appender);
}
}

View File

@ -0,0 +1,29 @@
package com.baeldung.designpatterns;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class TestAppenderDP extends AppenderSkeleton {
private final List<LoggingEvent> log = new ArrayList<LoggingEvent>();
@Override
public boolean requiresLayout() {
return false;
}
@Override
protected void append(final LoggingEvent loggingEvent) {
log.add(loggingEvent);
}
@Override
public void close() {
}
public List<LoggingEvent> getLog() {
return new ArrayList<LoggingEvent>(log);
}
}