Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
1.Proxy
2.Observer
3.Decorator
4.Chain of Responsibility
5.State
6.Builder
Proxy
“Placeholder”
public class Bitmap {
public Bitmap(String imageUrl) {
//...
}
// Resource-heavy operations
public void Render();
}
public interface BitmapProxiable {
public void render();
}
public class Bitmap implements BitmapProxiable {
public Bitmap(String imageUrl);
public void Render();
}
public class BitmapProxy implements BitmapProxiable {
private String mImageUrl;
private BitmapProxy(String imageUrl) {
mImageUrl = imageUrl;
}
public void render() {
Bitmap bitmap = new Bitmap(mImageUrl);
bitmap.render();
}
}
public class Client {
private BitmapProxiable mBitmap;
public void setup() {
mBitmap = new BitmapProxy(imageUrl);
}
public void render() {
mBitmap.render();
}
private void setBitmap(BitmapProxiable bitmap) {
mBitmap = bitmap;
}
}
Observer
public interface BluetoothObserver {
public void update(String newState);
}
public class Bluetooth {
private List<BluetoothObserver> mObservers = new ArrayList<>();
public void addObserver(BluetoothObserver observer) {
mObservers.add(observer);
}
public void removeObserver(BluetoothObserver observer) {
mObservers.remove(observer);
}
public void onStateChanged(String newState) {
for(BluetoothObserver observer : mObservers) {
observer.update(newState);
}
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(String newState) {
onStateChanged(newState);
}
}
}
public class Client {
private BluetoothObserver mObserver = new BluetoothObserver {
@Override
public void update(String newState) {
switch(newState) {
//...
}
}
}
public Client() {
Bluetooth.getInstance().addObserver(mObserver);
}
}
Decorator
“wrapping additional functionality”
public class Bitmap {
public void Render();
}
public class Frame {
// ...
}
public class Logo {
// ...
}
1. Common interface & non-optional base
public interface Graphic {
public void render();
}
public class Bitmap implements Graphic {
public void render() {
// draw bitmap
}
}
2. Base class for optionals (the decorator)
public abstract class GraphicDecorator implements Graphic
{
private Graphic mGraphic;
public GraphicDecorator(Graphic graphic) {
mGraphic = graphic;
}
}
3. Delegate to wrapped object
public abstract class GraphicDecorator implements Graphic
{
private Graphic mGraphic;
public GraphicDecorator(Graphic graphic) {
mGraphic = graphic;
}
public void render() {
mGraphic.render();
}
}
4. Make decorator
public class Frame extends GraphicDecorator {
public Frame(Graphic graphic) {
super(graphic);
}
public void render() {
super.draw(); // call base class
// draw frame
}
}
4. Make decorator
public class Logo extends GraphicDecorator {
public Logo(Graphic graphic) {
super(graphic);
}
public void render() {
super.draw(); // call base class
// draw Logo
}
}
Bitmap bitmap1 = new Bitmap(imageLink);
Frame frame1 = new Frame(bitmap);
frame1.render();
// Bitmap.render() -> Frame.render()
Bitmap bitmap2 = new Bitmap(imageLink2);
Frame frame2 = new Frame(bitmap2);
Logo logo2 = new Logo(frame2)
logo2.render();
// Bitmap.render() -> Frame.render() ->
Logo.render()
Bitmap bitmap3 = new Bitmap(imageLink3);
Logo logo3 = new Logo(bitmap3);
Logo logo3_1 = new Logo(logo3);
Frame frame3 = new Frame(logo3_1);
frame3.render();
// Bitmap.render() -> Logo.render() ->
Logo.render -> Frame.render()
Chain of Responsibility
debug info warning error
public enum LogLevel {
DEBUG,
INFO,
WARNING,
ERROR
}
public abstract class Logger {
private LogLevel mLevel;
public Logger(LogLevel level) {
mLevel = level;
}
private Logger mNextLogger;
public Logger setNext(Logger logger) {
mNextLogger = logger;
return mNextLogger;
}
public void log(String message, LogLevel level) {
if(level == mLevel) {
process(message);
} else if (mNextLogger != null) {
mNextLogger.log(message, level);
} else {
// There's no next level. Handle here.
}
}
protected abstract void process(String message);
}
public class DebugLog extends Logger {
@Override
protected void process(String message) {
System.out.println("DEBUG:: "+message);
}
}
public class InfoLog extends Logger {
...
}
public class WarningLog extends Logger {
...
}
public class ErrorLog extends Logger {
...
}
public class Client {
private Logger mLog;
public void setup() {
mLog = new DebugLog(LogLevel.DEBUG);
Logger infoLog = new InfoLog(LogLevel.INFO);
Logger warningLog = new InfoLog(LogLevel.WARNING);
Logger errorLog = new InfoLog(LogLevel.ERROR);
mLog.setNext(infoLog).setNext(warningLog).setNext(errorLog);
}
public void onError(String message, LogLevel level) {
mLog.log(message, level);
}
}
State
public abstract class ButtonState {
public abstract void handle(Button button);
// public abstract void handle();
}
public class ACState extends ButtonState {
public void handle(Button button) {
// toggle AC
}
}
public class FanState extends ButtonState {
public void handle(Button button) {
// toggle fan
}
}
public class LightState extends ButtonState {
public void handle(Button button) {
// toggle light
}
}
public class Button {
private ButtonState mCurrentState;
public Button(ButtonState defaultState) {
mCurrentState = defaultState;
}
public void setState(ButtonState state) {
mCurrentState = state;
}
public void click() {
mCurrentState.handle(this);
//mCurrentState.handle();
}
}
Button button = new Button(new ACState());
button.click(); // ACState.handle(button);
button.setState(new FanState());
button.click(); // FanState.handle(button);
Builder
https://jlordiales.me/2012/12/13/the-builder-pattern-in-practice/
public class User {
private final String firstName; //required
private final String lastName; //required
private final int age; //optional
private final String phone; //optional
private final String address; //optional
...
}
- Code is immutable – minimize possible state
- Has to set up with constructor, but also want some to be optional
public User(String firstName, String lastName) {
this(firstName, lastName, 0);
}
public User(String firstName, String lastName, int age) {
this(firstName, lastName, age, "");
}
public User(String firstName, String lastName, int age, String phone) {
this(firstName, lastName, age, phone, "");
}
public User(String firstName, String lastName, int age, String phone, String address)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.phone = phone;
this.address = address;
}
public User(String firstName, String lastName) {
this(firstName, lastName, 0);
}
public User(String firstName, String lastName, int age) {
this(firstName, lastName, age, "");
}
public User(String firstName, String lastName, int age, String phone) {
this(firstName, lastName, age, phone, "");
}
public User(String firstName, String lastName, int age, String phone, String address)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.phone = phone;
this.address = address;
}
1.More constructors = more code to maintain
2.Difficult for client code to use :
- Which one do I use?
- What if I want to set value for address but not age and
phone?
3.Difficult to read:
User user = new User("a", "b", 1, "c"); // ????
public class User {
private String firstName; // required
private String lastName; // required
...
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
...
}
Create empty object, then set only attributes I’m interested in?
public class User {
private String firstName; // required
private String lastName; // required
...
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
...
}
Create empty object, then set only attributes I’m interested in?
1. Inconsistent state. Client code may expect the object has already
been constructed, but it’s not.
2. Class is now mutable.
public class User {
...
private User(UserBuilder builder) {
this.firstName = builder.firstName;
...
}
public String getFirstName() {
return firstName;
}
…
// UserBuilder nested here
}
// Inside User (User.UserBuilder)
public static class UserBuilder {
private final String firstName;
...
public UserBuilder(String firstName,
String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
...
public User build() {
// Defaults & logic tests
return new User(this);
}
}
public class User {
...
private User(UserBuilder builder) {
this.firstName = builder.firstName;
...
}
public String getFirstName() {
return firstName;
}
…
// UserBuilder nested here
}
// Inside User (User.UserBuilder)
public static class UserBuilder {
private final String firstName;
...
public UserBuilder(String firstName,
String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
...
public User build() {
// Default values
return new User(this);
}
}
1.Constructor is private – must use Builder.
2.Class is now mutable again. We only provide getters.
3.Builder constructor receives the required parameters.
4.Provide defaults & logic checks in build()
User user = new User.UserBuilder("Adam", "John")
.age(30)
.phone("123456799")
.address("123 Road 34")
.build();
public User build() {
if (age > 120) {
// throw exception here is bad, not thread-safe
}
// Window of opportunity for second thread to alter
return new User(this);
}
public User build() {
User user = new user(this);
if (user.getAge() > 120) {
throw new IllegalStateException(“Age out of range”);
// thread-safe
}
return user;
}

More Related Content

Design patterns

  • 3. public class Bitmap { public Bitmap(String imageUrl) { //... } // Resource-heavy operations public void Render(); }
  • 4. public interface BitmapProxiable { public void render(); } public class Bitmap implements BitmapProxiable { public Bitmap(String imageUrl); public void Render(); }
  • 5. public class BitmapProxy implements BitmapProxiable { private String mImageUrl; private BitmapProxy(String imageUrl) { mImageUrl = imageUrl; } public void render() { Bitmap bitmap = new Bitmap(mImageUrl); bitmap.render(); } }
  • 6. public class Client { private BitmapProxiable mBitmap; public void setup() { mBitmap = new BitmapProxy(imageUrl); } public void render() { mBitmap.render(); } private void setBitmap(BitmapProxiable bitmap) { mBitmap = bitmap; } }
  • 8. public interface BluetoothObserver { public void update(String newState); }
  • 9. public class Bluetooth { private List<BluetoothObserver> mObservers = new ArrayList<>(); public void addObserver(BluetoothObserver observer) { mObservers.add(observer); } public void removeObserver(BluetoothObserver observer) { mObservers.remove(observer); } public void onStateChanged(String newState) { for(BluetoothObserver observer : mObservers) { observer.update(newState); } } private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(String newState) { onStateChanged(newState); } } }
  • 10. public class Client { private BluetoothObserver mObserver = new BluetoothObserver { @Override public void update(String newState) { switch(newState) { //... } } } public Client() { Bluetooth.getInstance().addObserver(mObserver); } }
  • 12. public class Bitmap { public void Render(); } public class Frame { // ... } public class Logo { // ... }
  • 13. 1. Common interface & non-optional base public interface Graphic { public void render(); } public class Bitmap implements Graphic { public void render() { // draw bitmap } }
  • 14. 2. Base class for optionals (the decorator) public abstract class GraphicDecorator implements Graphic { private Graphic mGraphic; public GraphicDecorator(Graphic graphic) { mGraphic = graphic; } }
  • 15. 3. Delegate to wrapped object public abstract class GraphicDecorator implements Graphic { private Graphic mGraphic; public GraphicDecorator(Graphic graphic) { mGraphic = graphic; } public void render() { mGraphic.render(); } }
  • 16. 4. Make decorator public class Frame extends GraphicDecorator { public Frame(Graphic graphic) { super(graphic); } public void render() { super.draw(); // call base class // draw frame } }
  • 17. 4. Make decorator public class Logo extends GraphicDecorator { public Logo(Graphic graphic) { super(graphic); } public void render() { super.draw(); // call base class // draw Logo } }
  • 18. Bitmap bitmap1 = new Bitmap(imageLink); Frame frame1 = new Frame(bitmap); frame1.render(); // Bitmap.render() -> Frame.render()
  • 19. Bitmap bitmap2 = new Bitmap(imageLink2); Frame frame2 = new Frame(bitmap2); Logo logo2 = new Logo(frame2) logo2.render(); // Bitmap.render() -> Frame.render() -> Logo.render()
  • 20. Bitmap bitmap3 = new Bitmap(imageLink3); Logo logo3 = new Logo(bitmap3); Logo logo3_1 = new Logo(logo3); Frame frame3 = new Frame(logo3_1); frame3.render(); // Bitmap.render() -> Logo.render() -> Logo.render -> Frame.render()
  • 22. debug info warning error public enum LogLevel { DEBUG, INFO, WARNING, ERROR }
  • 23. public abstract class Logger { private LogLevel mLevel; public Logger(LogLevel level) { mLevel = level; } private Logger mNextLogger; public Logger setNext(Logger logger) { mNextLogger = logger; return mNextLogger; } public void log(String message, LogLevel level) { if(level == mLevel) { process(message); } else if (mNextLogger != null) { mNextLogger.log(message, level); } else { // There's no next level. Handle here. } } protected abstract void process(String message); }
  • 24. public class DebugLog extends Logger { @Override protected void process(String message) { System.out.println("DEBUG:: "+message); } } public class InfoLog extends Logger { ... } public class WarningLog extends Logger { ... } public class ErrorLog extends Logger { ... }
  • 25. public class Client { private Logger mLog; public void setup() { mLog = new DebugLog(LogLevel.DEBUG); Logger infoLog = new InfoLog(LogLevel.INFO); Logger warningLog = new InfoLog(LogLevel.WARNING); Logger errorLog = new InfoLog(LogLevel.ERROR); mLog.setNext(infoLog).setNext(warningLog).setNext(errorLog); } public void onError(String message, LogLevel level) { mLog.log(message, level); } }
  • 26. State
  • 27. public abstract class ButtonState { public abstract void handle(Button button); // public abstract void handle(); }
  • 28. public class ACState extends ButtonState { public void handle(Button button) { // toggle AC } } public class FanState extends ButtonState { public void handle(Button button) { // toggle fan } } public class LightState extends ButtonState { public void handle(Button button) { // toggle light } }
  • 29. public class Button { private ButtonState mCurrentState; public Button(ButtonState defaultState) { mCurrentState = defaultState; } public void setState(ButtonState state) { mCurrentState = state; } public void click() { mCurrentState.handle(this); //mCurrentState.handle(); } }
  • 30. Button button = new Button(new ACState()); button.click(); // ACState.handle(button); button.setState(new FanState()); button.click(); // FanState.handle(button);
  • 32. public class User { private final String firstName; //required private final String lastName; //required private final int age; //optional private final String phone; //optional private final String address; //optional ... } - Code is immutable – minimize possible state - Has to set up with constructor, but also want some to be optional
  • 33. public User(String firstName, String lastName) { this(firstName, lastName, 0); } public User(String firstName, String lastName, int age) { this(firstName, lastName, age, ""); } public User(String firstName, String lastName, int age, String phone) { this(firstName, lastName, age, phone, ""); } public User(String firstName, String lastName, int age, String phone, String address) { this.firstName = firstName; this.lastName = lastName; this.age = age; this.phone = phone; this.address = address; }
  • 34. public User(String firstName, String lastName) { this(firstName, lastName, 0); } public User(String firstName, String lastName, int age) { this(firstName, lastName, age, ""); } public User(String firstName, String lastName, int age, String phone) { this(firstName, lastName, age, phone, ""); } public User(String firstName, String lastName, int age, String phone, String address) { this.firstName = firstName; this.lastName = lastName; this.age = age; this.phone = phone; this.address = address; } 1.More constructors = more code to maintain 2.Difficult for client code to use : - Which one do I use? - What if I want to set value for address but not age and phone? 3.Difficult to read: User user = new User("a", "b", 1, "c"); // ????
  • 35. public class User { private String firstName; // required private String lastName; // required ... public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } ... } Create empty object, then set only attributes I’m interested in?
  • 36. public class User { private String firstName; // required private String lastName; // required ... public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } ... } Create empty object, then set only attributes I’m interested in? 1. Inconsistent state. Client code may expect the object has already been constructed, but it’s not. 2. Class is now mutable.
  • 37. public class User { ... private User(UserBuilder builder) { this.firstName = builder.firstName; ... } public String getFirstName() { return firstName; } … // UserBuilder nested here } // Inside User (User.UserBuilder) public static class UserBuilder { private final String firstName; ... public UserBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public UserBuilder age(int age) { this.age = age; return this; } ... public User build() { // Defaults & logic tests return new User(this); } }
  • 38. public class User { ... private User(UserBuilder builder) { this.firstName = builder.firstName; ... } public String getFirstName() { return firstName; } … // UserBuilder nested here } // Inside User (User.UserBuilder) public static class UserBuilder { private final String firstName; ... public UserBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public UserBuilder age(int age) { this.age = age; return this; } ... public User build() { // Default values return new User(this); } } 1.Constructor is private – must use Builder. 2.Class is now mutable again. We only provide getters. 3.Builder constructor receives the required parameters. 4.Provide defaults & logic checks in build()
  • 39. User user = new User.UserBuilder("Adam", "John") .age(30) .phone("123456799") .address("123 Road 34") .build();
  • 40. public User build() { if (age > 120) { // throw exception here is bad, not thread-safe } // Window of opportunity for second thread to alter return new User(this); }
  • 41. public User build() { User user = new user(this); if (user.getAge() > 120) { throw new IllegalStateException(“Age out of range”); // thread-safe } return user; }