[Design Pattern] Decorator Pattern in Depth

ทำไมต้องใช้ Decorator Pattern

  • อยากเพิ่มความสามารถของ Object (Object ทำงานเหมือนเดิมนะ แต่ถูกเพิ่มความสามารถ)

เมื่อไหร่ควรจะใช้

  • ไม่อยากใช้คุณสมบัตินึงของ OOP-Inheritance มากเกินไป เพราะใช้ไปแล้ว ก็ต้อง Override ไปแก้ความสามารถที่ได้มาจาก Class แม่อีก หรือมี Class ลูก (Sub Class) ที่มากจนเกินไปครับ ซึ่งเจ้า Decorator มันมาช่วยตรงนี้ครับ ไม่ต้องแก้ แต่เราเพิ่ม (Wrap) ความสามารถใหม่ลงไป โดยที่ความสามารถเดิม ยังคงอยู่ ลดจำนวน Sub Class ลงได้
  • สนับสนุนแนวคิด Open-Close Principle ด้วย

Open for Extension Closed for Modification

  • Note: ไม่บอกว่าห้ามใช้ Inheritance นะครับ ใช้ให้มันพอดี ^__^

Pattern มันเป็นอย่างไร - Class Diagram

  • Template
  • ตัวอย่าง

มุมมองตอน Runtime - Object Diagram

  • ลักษณะของ Object หลังถูก Create

มุมมองลำดับการทำงาน - Sequence Diagram

  • ตอนสร้าง Object
  • ตอนคำนวณราคา

Real World Example

  • Java.IO Class ไง มีการเพิ่มความสามารถจาก
    • FileInputStream
      • BufferedInputStream
        • UpperCaseInputStream - สร้างเอง
  • Code ของ Class UpperCaseInputStream เสริมความสามารถมาจาก FilterInputStream
import java.io.*;
public class UpperCaseInputStream extends FilterInputStream {

    public UpperCaseInputStream(InputStream in) {
        super(in);
    }

    public int read() throws IOException {
        int c = super.read();
        return (c == -1 ? c : Character.toUpperCase((char)c));
    }

    public int read(byte[] b, int offset, int len) throws IOException {
        int result = super.read(b, offset, len);
        for (int i = offset; i < offset+result; i++) {
            b[i] = (byte)Character.toUpperCase((char)b[i]);
        }
        return result;
    }
}
  • มาดู Code กันดีว่า ว่าเพิ่มความสามารถอย่างไร ? - อ่าน TestFile ซึ่ง FileInputStream มันอ่านที่ได้ละ 1 byte / โดยให้อ่านมาเป็น Stream ที่ละ 8192 byte ใช้ BufferedInputStream ลด Operation ที่แสนหนักหน่วงไป และอ่านให้แปลงตัวอีกษรให้เป็นตัวพิมพ์ใหญ่ (UpperCase) จาก UpperCaseInputStream
public class SampleDecoratorTest {
    public static void main(String[] args) throws IOException {
        int char;
        try {
            InputStream in = new UpperCaseInputStream(new BufferedInputStream(new FileInputStream(“DecoratorTest.txt”)));
            while((char = in.read()) >= 0) {
                System.out.print((char)char);
            }
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}