SOLID Principle (Part 1+2)

SOLID Principle (Part 2)
LSP: Liskov Substitution Principle


LSP ကိုအစပြုခဲ့တဲ့သူက MIT က Professor Barbara Liskov ဆိုတဲ့ဘွားတော်ပဲဖြစ်ပါတယ်။ ဘွားတော်က ACM Turing Award Winner လဲဖြစ်ပါတယ်။ ACM Turing Award ဆိုတာ Alan Turing ကို ဂုဏ်ပြုပြီး ပေးထားတဲ့ Computer Science မှာ အမြင့်ဆုံး ဆုပါပဲ။ Language Designer တွေ OS Designer တွေ Computer Science ကိုတနည်းတဖုံပြောင်းလဲပေးခဲ့တဲ့သူတွေပဲရကြပါတာပါ။ Dennis Ritchie (C language Designer) နဲ. Ken Thompson တို.လဲ ရဖူးပါတယ် UNIX ကို သူတို.နှစ်ယောက်လုပ်ခဲ့ကြလို.ပါ။ Liskov က CLU နဲ. Argus ဆိုတဲ့ Programming Languge ၂ခု ရဲ. designer ပါ။ အဲ့ language တွေက OOP ကိုပြောင်းလဲစေခဲ့ပါတယ်။ တခါတလေ ပြောနေကြတဲ့ ငါတို. langauge က feature ကို ဟိုဘက်က langauge က ခိုးသွားတယ်ဆိုတာမျိုး ကြားဖူးမှာပါ။ တကယ်ကရီစရာပါ modern language တော်တော်များများက သူတို.ကိုယ်ပိုင် concept ဆိုတာထက် ရှေးက langauge concept တွေအပေါ်ထပ်ကောင်းအောင် လုပ်ထားကြတာပါပဲ။



LSP အနှစ်ချုပ်ကတော့ အောက်ပါအတိုင်းပါပဲ။



Methods that use references to the base classes must be able to use the objects of the derived classes without knowing it



OO မှာ program တွေဟာ inheritance ကိုသုံးပြီး class heirarchy တွေဆောက်ကြပါတယ်။ အဲ့ဒီမှာ base class (parent class, super class, super type) ရဲ. reference ကိုသုံးထားတဲ့နေရာမှာ child class (derived class,subtype, sub class) ရဲ. object ကို child class object သည် ဘာ class ဆိုတာမျိုး သိစရာမလိုပဲ သုံးလို.ရ ရမယ်လို.ဆိုပါတယ်။ နည်းနည်းထပ်ရှင်းပါဦးမယ်။ parent reference သုံးထားတဲ့ method တွေမှာ child object တွေကို parent object တွေနေရာမှာ အစားထိုးသုံးလို.ရရမယ်။ အဲ့လိုသုံးလို.ရဖို. ဘယ်လို knowledge မှမလိုဘူး။ (ဒီနေရာ မှာ knowledge ဆိုတာ part1 ကပြထားတဲ့ open close principle example မှာပြထားတဲ့ instanceof operator နဲ.စစ်တာမျိုးကိုပါ)။ ဒါကို LSP Liskov Substitution principle လို.ပြောပါတယ်။ Subsitution ကဘာကိုဆိုလိုချင်တာလဲဆိုတော့ child object တွေသည် parent refernece သုံးတဲ့နေရာမှာ ဘာမှအပြောင်းအလဲမရှိပဲ သုံးနိုင်ရမယ်။ child class က object သည် parent class နေရာမှာ semantically equalivent အနေနဲ့သုံးနိုင်ရမယ်။ code သည် child object ကိုသုံးနေတာလား parent object ကိုသုံးနေတာလားဆိုတာကို သိစရာကိုမလိုဘူး ။ အစားထိုးနိုင်ရမယ် ဒါကိုပြောချင်တာပါ။ နဂို parent reference ကိုသုံးထားတဲ့ code ကိုပြုပြင်စရာမလိုပဲ parent reference နေရာမှာ child object ကိုသုံးနိုင်ရမယ်။ ဒါမှသာလျှင် နောက်ထပ် functionality အသစ်ထဲ့တာလိုနေရာမျိုးမှာ မူရင်း code ကိုမထိပဲပြင်လို.ရမှာပါ။ extensible ဖြစ်အောင် ရယ် maintenance ကောင်းအောင်လို.ပြောရင် ရမှာပါ။ LSP သည် inheritance ကို နည်းမှန်လမ်းမှန်သုံးနိုင်အောင် ပြထားတဲ့ principle လို.ပြောရမှာပါ။ LSP က OCP နဲ.ဆက်စပ်နေပါတယ်။ LSP ကိုချိုးဖောက်ပြီဆိုရင် OCP ကို ချိုးဖောက်သလိုလဲဖြစ်နိုင်ပါတယ်။



Inheritance hierarchy တွေချတဲ့နေရာမှာ child class (subtype) သည် parent class (super type) ရဲ. semantic အတိုင်း လိုက်နာရပါလိမ့်မယ်။ ဆိုချင်တာက child class မှာ override လုပ်ထားတဲ့ parent ရဲ. method တွေသည် paernt ရဲ. nature နဲ. semantically မတူဘူးဆိုရင် ဒါ LSP ကိုချိုးဖောက်တာပါပဲ။ ဒီ https://sanaulla.info/2011/11/28/solid-liskov-substitution-principle-2/ link ကဥပမာလေးကိုပြင်ပြီး ပေးပါရစေ ရှင်းလွယ်လို.ပါ။



class Bird {
public void fly(){}
public void eat(){}
}
class Crow extends Bird {}
class Penguin extends Bird{
fly(){
throw new UnsupportedOperationException(); // violate LSP here
}
}

public BirdTest{
public static void main(String[] args){
List<Bird> birdList = new ArrayList<Bird>();
birdList.add(new Bird());
birdList.add(new Crow());
birdList.add(new Penguin());
letTheBirdsFly ( birdList );
}
static void letTheBirdsFly ( List<Bird> birdList ){
for ( Bird b : birdList ) {
b.fly();
}
}
}



အပေါ်က example မှာ LSP ကိုချိုးဖောက်ထားတာကိုပြထားပါတယ်။ Bird ဆိုတဲ့ class ကနေ Crow ရယ် Penguin ရယ်က extend လုပ်ပါတယ်(subtyping)ပေါ့။ Bird မှာ fly ဆိုတာပါပါတယ်။ Crow ကတော့ ပျံနိုင်ပါတယ် ဒါဆို Bird fly ကိုသုံးရင် သူ. fly ကိုလဲသုံးလို.ရပါတယ်။ Penguin ကတော့မပျံနိုင်ပါဘူး ဒါကြောင့် သူ. method မှာ exception ကို လွှင့်ခိုင်းလိုက်ပါတယ်။ အဓိက Penguin သည် မပျံနိုင်ပါဘူး ဒါကြောင့် Bird ရဲ. fly သူ.မှာမရှိတဲ့အတွက် bird fly ကိုသုံးထားတဲ့ code တွေမှာ penguin သည် အလုပ်လုပ်နိုင်မှာမဟုတ်ပါဘူး။ ဒါဆိုရင် ကျွန်တော်တို.ရဲ. b.fly() code ကိုလိုက်ပြင်နေရတာမျိုးဖြစ်နေပါလိမ့်မယ်။ ဒါက LSP ကိုမလိုက်နာတဲ့အတွက် OCP ကိုပါ ထိသွားတာကိုမြင်နိုင်ပါလိမ့်မယ်။ LSP ကပေးချင်တဲ့ theme ကတော့ child class တွေကို extend လုပ်တဲ့အခါမှာ သူတို. method တွေဟာ parent method တွေနဲ. အစားထိုးသုံးလို.ရ ရပါလိမ့်မယ်ဆိုတာပါပဲ။

Interface Segregation principle (ISP)


ဒီ principle ကတော့ရှင်းပါတယ် မလိုအပ်ပဲနဲ. interface တွေမှာ method တွေ အများကြီးစုပြုံထားတာမလုပ်ရဘူးလို.ပြောချင်တာပါ။ အဲ့လို စုပြံုထားတော့ အဲ့ interface ကို implements လုပ်တဲ့ class တွေဟာ မလိုအပ်ပဲနဲ. တခြား method တွေကိုပါ လိုက်ရေးရတာမျိုးပါ။ အဲ့အစား interface လေးတွေ အများကြီး ထပ်ခွဲပြီး တခုချင်းဆီမှာ ဆိုင်တဲ့ method လေးတွေ ပဲထဲ့သင့်ပါတယ်။ ဒါကလဲ single responsibility (SRP) နဲ.ကိုက်ညီအောင် လုပ်လိုက်တဲ့သဘောပါပဲ။ Fat Interface မလုပ်ပဲနဲ. small interface လေးတွေပဲခွဲခိုင်းတာပါ။ client class တခုဟာ သူမသုံးတဲ့ သူ.အတွက်မလိုအပ်တဲ့ method တွေကို fat interface ကြောင့် လိုက် override လုပ်နေရရင် မကောင်းပါဘူး။

Dependency Inversion Principle (DIP)


သူ.ရဲ. main rule ၂ခုကတော့အောက်ပါအတိုင်းပါပဲ။



High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend upon details. Details should depend upon abstractions.



အပေါ်က ၂ကြောင်းကိုမရှင်းခင်မှာ Abstraction ဆိုတာကိုအရင်ရှင်းရပါလိမ့်မယ်။ Abstraction ဆိုတာ program module သို.မဟုတ် code တွေကို detail implementation ကိုသိစရာမလိုပဲ သုံးနိုင်အောင် အလုပ်လုပ်နိုင်အောင် လုပ်ပေးထားတာကို abstraction လို.ဆိုချင်တာပါ။ All implementation detail ကို client မမြင်ရအောင် abstract လုပ်ထားတာပါ။ အဲ့တော့ implementation ကပြောင်းမယ်ဆိုရင်လဲ client အနေနဲ. အဲ့ဒီ changes ကိုသိစရာမလိုတော့ဘူးပေါ့ဗျာ။

Depend on Abstraction


အဲ့တော့ depend on abstraction ကိုရှင်းရရင် class တွေ code တွေ module တွေဟာ concrete class (interface မဟုတ် abstract class မဟုတ်သော class များ) တွေ သုံးပြီး relation မချိတ်ပဲ မသုံးပဲ relationship အားလုံးကို abstract class သို.မဟုတ် interface ကိုသုံးပြီး model လုပ်တာကိုဆိုချင်တာပါ။ အဲ့တော့ ကျွန်တော်တို.က class တခုက တခြား class တခုကို သုံးဖို.လိုပြီဆိုရင် concrete class အစား abstract class သို.မဟုတ် interface ကိုသုံးတာက ပိုပြီး ကောာင်းတယ်လို.ဆိုချင်တာပါ။ ဒါကို depened on abstraction ရဲ.သဘောပေါပဲ။ ဘာလို.လဲဆိုတော့ concrete class ကိုသုံးမယ်ဆိုရင် ကျွန်တော်တို.က သူ. class ရဲ. variable တွေ implementation detail တွေကို accidentally ယူသုံးမိနိုင်ပါတယ်။ interface ,abstract class တွေမှာတော့အဲ့လို မရှိနိုင်ပါဘူး။ နောက်ပြီး interface,abstract class သုံးမယ်ဆိုရင် သူ.တို.ရဲ. dervied class တွေ implementation ပြောင်းလဲ interface method တွေအပေါ်မှာပဲ မူတည်ပြီး သုံးထားတာဖြစ်တဲ့အတွက် code က changes လုပ်စရာမလိုပါဘူး။ဒါက depend on abstraction ရဲ. ကောင်းကျိုးပေါ့ဗျာ။ အဲ့တော့ module တခုနဲ.တခုကြားမှာ inteface တွေသုံးပြီးတော့ပဲ program dependency ကို create လုပ်သင့်တယ်လို.ဆိုလိုတာပါ။ ဥပမာ Java Spring Framework မှာဆို DAO, Service layer တွေမှာ interface ကိုသုံးထားခြင်းဟာ DI principleအတွက် depence upon abstraction ကိုလိုက်နာထားတာပါပဲ။

Dependency


class တခု module တခုက တခြား class တစ်ခုကို reference လုပ်ရပြီ ယူသုံးရပြီဆိုရင် ဒါဟာ dependency ပါပဲ။ အောက်က ဥပမာကိုကြည့်ပါ။



class Computer
{
Mouse mouse;
public setMouse(Mouse m)
{
this.mouse = m;
}
}
class Mouse
{
//mouse implementation
}



အပေါ်က code example မှာ Computer class ဟာ Mouse class ကို ယူသုံးထားပါတယ် ဒါက dependency ပါ။ ဒါဆိုရင် ဘာအားနည်းချက်ရှိလဲပေါ့ အဲ့ code မှာ Mouse သည် concrete class ဖြစ်ပါတယ် (ဒီနေရာမှာ Java class တွေက extend လုပ်ပြီး method တွေက virtual method ဖြစ်တာကြောင့် မသိသာပါဘူး C++ မှာဆို ရင်တော့သိသာပါပြီ)။ ဒါကြောင့် ကျွန်တော်တို.က တခြား Mouse တခုခုနဲ.အစားထိုးဖို. အဆင်မပြေနိုင်ပါဘူး ဘာလို.လဲဆိုတော့ကျွန်တော်တို.က Mouse class ရဲ. implementation အပေါ်မှာ directly depend ဖြစ်နေလို.ပါ။ ဒါဆိုကျွန်တော်တို.က concrete class Mouse အပေါ်မှာ တိုက်ရိုက်မမှီခိုပဲ အောက်ကလို ရေးလိုက်မယ်ဆိုရင် ဒါက Dependency Inversion ပါပဲ။



class Computer
{
IMouse mouse;
public setMouse(IMouse m)
{
this.mouse = m;
}
}
interface IMouse
{
//mouse methods



}
class WirelessMouse implements IMouse
{}



class USBMouse implements IMouse
{}



အပေါ်က code မှာ ပထမ ဥပမာနဲ.မတူပဲ Computer class ဟာ concrete mouse class (WirelessMouse,USBMouse) တွေအပေါ်မှာ direct dependency မရှိတော့ပဲ interface IMouse အပေါ်မှာပဲ dependence ဖြစ်သွားပါပြီ။ Concrete class အပေါ်မှာ dependence ဖြစ်နေတာကို interface ကိုပြောင်းပြီး dependency ကို inverse လုပ်လိုက်တာပါ။ အကျိုးဆက်ကတော့ကျွန်တော်တို.က Computer class က ကြိုက်တဲ့mouse implementation ကိုအစားထိုးသုံးလို.ရတာပါပဲ။ Dependency Inversion နဲ. Dependency Injection ကမတူပါဘူး ဒါပေမဲ့ ဆက်စပ်မှူတော့ရှိပါတယ်။ Dependency Inversion က Dependency တွေကိုရွှေ.တာဖြစ်ပြီးတော့ Dependency Injection ကတော့ Dependence Object တွေကို Dependency Injection Container တခုသုံးပြီး system ကနေ dependency တွေကို ထဲ့ပေးတာကိုပြောတာပါ။

Original link =>(https://m.facebook.com/story.php?story_fbid=pfbid0mmiLsqtDGhSHZz3PCzASYp7Rd1nNCVzsm6MyNPVfzfNMGRkTcTtQBYApNeAjecHnl&id=1819241055&mibextid=Nif5oz)

Leave a comment