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;
}
}
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()
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();
}
}
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;
}