Composite Pattern

Composite Pattern ကတော့ structural design pattern ဖြစ်ပါတယ်။ Composite က Tree Structure တွေ မှာ အသုံးများပါတယ်။ Tree Structure ပြဿနာတွေ ဆိုရင် Composite လို့ ဆိုလို့ရတယ်။

ဥပမာ File Structure တစ်ခုကို ကြည့်ရအောင်။ Folder တစ်ခု အောက်မှာ Folder လည်း ရှိတယ်။ File လည်း ရှိနိုင်ပါတယ်။ Linux က file system တွေမှာ ဆိုရင် root(/) အောက်မှာ အခါ folder နဲ့ file တွေ ရှိပြီး အဆင့်ဆင့် ခွဲ သွားတာ မျိုးပေါ့။

/
/var/
/var/www/
/var/www/html/
/var/www/html/index.html
/var/www/html/hello.html

Composite Pattern မသုံးပဲ​ ဆောက်မယ် ဆိုရင် class Diagram က အောက်ကလို ဖြစ်နေမှာပါ။


ဒီ Class Diagram မှာ အဓိ ပြဿနာက File အပြင် short cut ထပ်ဖြည့်မယ်ဆိုရင် Directory ထဲမှာ ထပ်ပြင်ရမယ်။ Open Close Principle နဲ့ မကိုက်တော့ဘူး။ တစ်ခု ထပ်လာတိုင်း တစ်ခါ ထပ်ပြင်နေရမှာပါ။

အဲဒီ လို ပြဿနာတွေ အတွက် Composite ကို သုံးပါတယ်။

Composite Pattern ကတော့ အောက်ကလို Clas Diagram ပါ။


Directory ဟာ Component Interface ကို Implement လုပ်ထားပြီး Directory ထဲ မှာ Component ထပ်ပါသေးတယ် လို့ ပြထားပါတယ်။

Code ကို ကြည့်ရအောင်။

FileComponent.java

public abstract class FileComponent { 

    protected String name;

    public FileSystemComponent(String name) { 
        this.name = name;
    }
    
    public abstract void print();
    
    public abstract int getSize(); 
    
}

File.java

public class Directory extends FileComponent {
    protected Collection<FileSystemComponent> fileSystemComponents = new ArrayList<FileSystemComponent>();

    public Directory(String name) { 
        super(name);
    }
    
    public void addComponent(FileSystemComponent component) { 
        fileSystemComponents.add(component);
    }
    
    public int getSize() {
        int sizeInBytes = 0;
        for (FileSystemComponent component : fileSystemComponents) {
            sizeInBytes += component.getSize(); 
        }
        return sizeInBytes;
  }
  
    public void print() {
        System.out.println("-- dir " + name + " size=" + getSize() + " bytes"); 
        
        for (FileSystemComponent component : fileSystemComponents) {
            component.print(); 
        }
    } 
}

ဒီ code မှာ ဆိုရင် Directory အောက်မှာ File လည်း ရှိနိုင်သလို Directory လည်း ရှိနိုင်ပါတယ်။

အဲဒီ အတွက် getSize() ကို ခေါ်လိုက်ရင် child component တွေ ရဲ့ getSize() ကို ဆင့်ကာ ဆင့်ကာ ခေါ်ပြီး File Size ကို ရနိုင်ပါတယ်။

Pros and Cons

ကောင်းတာကတော့ Complex ဖြစ်သည့် Tree Structure တွေကို ရှင်းရှင်းလင်းလင်း ဖြစ်သွားစေပါတယ်။

Open/Close Principle ကို လိုက်နာထားတယ်။ File အပြင် short cut ထပ်ဖြည့်လည်း Directory က ဘာမှ ထပ်ပြင်ဖို့ မလိုတော့ပါဘူး။

မကောင်းတာကတော့ တူညီသည့် Structure မရှိသည့် Component တွေမှာ interface တွေ အများကြီး ထပ်သုံးနေရလိမ့်မယ်။ ဥပမာ File မှာ getSize ရှိပေမယ့် ShotCut မှာ getSize မရှိသည့် အခါ။ နောက်ပြီး Vault Directory ဆိုပြီး ထပ်ဖြည့်သည့် အခါမှာ interface တွေ ထပ်ပေါင်း ထည့်ရပြီး interface တွေ အများကြီး ဖြစ်သွားနိုင်ပါတယ်။