物件導向五大基本原則(二)_物件導向

來源:互聯網
上載者:User
前言

時間如梭,少年仍在奔跑。。。 Ⅰ.裡氏替換原則

簡述:關於裡氏替換原則,可能在每天的代碼中都有出現關於這一原則的使用,只是一直都在使用,而沒有意識到這就是所謂的裡氏替換原則。裡氏替換原則的思想是:”基類可實現的功能,子類也可以實現”,

下面代碼,假設有一個List參數的方法C,裡面的邏輯是根據索引找到相應的集合元素,那麼當需要list的實作類別的索引尋找功能時,可以將list的實作類別(ArrayList、LinkedList等)任意一個作為方法C的參數傳入,類似這樣的代碼可能每天都會遇到,可這就是裡氏替換原則的體現;

public String C(List<String> contents,int index){        return contents.get(index);    }   

下面代碼,接著假設有一個方法D聲明的傳回型別是List,可下面代碼真實返回的類型卻是ArrayList,而調用者並不知道返回的類型是ArrayList,只知道給其返回了List,這也是裡氏替換原則的體現;

public List<Integer> D(){        //...省略        //ArrayList<Integer> ids = new ArrayList<Integer>;        return id;}

上面列舉的兩個例子都是集合中介面和實作類別之間的關係,也就是基類與子類的關係。基類可以實現的功能,子類可以代替基類實現相應的功能,這也是java物件導向特性的體現,所以在java語言裡,更實在的體現出了裡氏替換原則。其實在開發中的代碼,裡氏替換原則應該是隨處可見的,再看看下面的代碼,是不是跟上面都同樣的體現;

//主函數  class App{        public static void main(String args[]){            ArrayList<String> str = getHappyNeyYear();            NewYearFactory newYearFactory = new NewNewYearFactoryImpl();            List<Integer> year = newYearFactory.createNewYear(str);        }    }    //示範介面    interface NewYearFactory{        List<Integer> createNewYear(List<String> strContent);    }    //實作類別    class NewYearFactoryImpl implements NewYearFactory{        @Override        public List<Integer> createNewYear(List<String> strContent) {            ArrayList<Integer> year = api.getYear(strContent);            return year;        }   }
總結:基類可實現的功能,子類同樣可以實現,在繼承或實現中,子類延續了基類的特性。 Ⅱ.介面隔離原則

簡述:介面隔離原則的核心思想是要求介面不要過於通用,須追求專一的功能.

假設下面Hobit介面是提供給開發人員選擇愛好的,而剛好A同學的愛好是逛街,那麼A同學是不是就要重寫Hobit介面,接著實現shoppting函數的邏輯代碼.

public interface Hobit{        void coding();        void readBook();        void shopping();    }    public static void doHobit(){         Hobit hobit = new Hobit() {            @Override            public void coding() {            }            @Override            public void readBook() {            }            @Override            public void shopping() {                //...            }        };    }

上面假設A同學的愛好是逛街,可在實現Hobit介面的時候卻也得實現coding和readBook這兩個方法,這不是多餘嗎。那麼可以去掉這兩個方法嗎。 假如去掉這兩個方法,這時候剛好B同學的愛好是讀書,那麼Hobit介面沒有了readBook這個方法,又該怎麼辦呢。

上面的假設會不會覺得貌似很矛盾,介面太通用,會覺得出現多餘的代碼;介面太專一,那多出來的功能又該怎麼實現呢。如果你熟悉Android關於設定控制項(比如TextView、Button等)的點擊事件/長按事件/觸摸事件,或許你會恍然大悟,看看下面的代碼,怎麼實現設定控制項的點擊事件

button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {            }});button.setOnLongClickListener(new View.OnLongClickListener() {            @Override            public boolean onLongClick(View v) {                return false;            }});button.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                return false;            }});

點擊事件由OnClickListener介面負責,長按事件由OnLongClickListener介面負責,觸摸事件由OnTouchListener介面負責,開發人員要處理什麼事件,只需要實現相應的介面。這樣的話不是可以解決上面出現的兩個問題 介面通用導致代碼多餘的問題; 介面專一導致功能欠缺的問題.

接著再看看下面關於Android屬性動畫監聽的介面實現,是不是覺得Android系統關於實現動畫的監聽怎麼違背了介面隔離原則,實現動畫監聽介面,還得重寫裡面的四個方法,太多餘了吧。其實可能Android系統開發人員當初在設計這個介面的時候,考慮到開發人員可能需要同時使用到其中幾個方法,所以一併提供了.當然,這也有好處,也是有壞處的,為了完善這個介面,Android系統開發人員也重新提供了另一介面AnimatorListenerAdapter,在該介面中已對AnimatorListener的方法進行了空實現,開發人員只需要重寫所需的方法即可.

Button button = new Button(this);     ObjectAnimator animator = ObjectAnimator.ofFloat(button, "rotationX", 0, 360);     animator.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {            }            @Override            public void onAnimationEnd(Animator animation) {            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }});
總結:在開發中,應追求專一介面,這樣可以避免很多的問題;那麼假設你在開發項目的第一版本時,寫了上面的Hobit介面,當某天由於需求變更而得去增加愛好選項,那麼這時是否將增加的愛好選項添加到Hobit介面裡,這樣是不是會導致項目之前所有實現Hobit介面的地方都得變更,這樣就麻煩~~,所以專一介面是能避免很多問題的 附加:上面Hobit介面關於愛好的,或許列舉得不是很好,但大致瞭解就好. Ⅲ.依賴倒置原則

在傳統軟體的開發中,通常是介面或抽象類別依賴於具體類,當具體類有變動,那麼就得改變其介面或抽象類別,而依賴倒置原則的出現,正是將這一傳統的依賴倒置過來,使得具體類依賴於介面或抽象類別。

現在假設有這麼一需求,使用者輸入資訊後點擊提交,系統負責讀取、校正和永久儲存,下面是Android代碼實現:

findViewById(R.id.tv_submit).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                String userInput = mEditText.getText().toString();                if(!TextUtils.isEmpty(userInput) && inputNews.check(userInput)){   //驗證輸入的資料是否符合商務邏輯                    SQLiteDatabase db = new DbOpenHelper(ProviderActivity01.this).getWritableDatabase();                    ContentValues contentValues = new ContentValues();                    contentValues.put("input", userInput);                    db.insert("user", null, contentValues);                }else{                    Toast.makeText(ProviderActivity01.this,"抱歉,你輸入的資料不合法",Toast.LENGTH_SHORT).show();                }            }});

一個普遍的現象,高層級模組依賴於底層級模組,比如上面代碼中的UI層依賴業務層,業務層依賴資料層。那麼如何用抽象來實現依賴倒置原則,解決上面高層模組依賴底層模組的現象呢。另一方面,我們也不想要一個簡單的完整的類來完成所有的事情,這時就可以想到單一職責原則,將各個職能進行劃分,來最佳化上面的代碼.

資料層

public interface DataLayer {        void insert(String value);    }       /**實作類別*/public class DataLayerImpl implements DataLayer{        private Context mContext;        public DataLayerImpl(Context context){            mContext = context;        }        @Override        public void insert(String value){            SQLiteDatabase db = new DbOpenHelper(mContext).getWritableDatabase();            ContentValues contentValues = new ContentValues();            contentValues.put("input",value);            db.insert("user",null,contentValues);        }    }

業務層

public interface BusinessLayer {        void check(String str);    }    /**實作類別*/public class BusinessLayerImpl implements BusinessLayer {        private DataLayer mDataLayer;        public BusinessLayerImpl(DataLayer mDataLayer) {            this.mDataLayer = mDataLayer;        }        @Override        public void check(String str){            //...商務邏輯校正,略            mDataLayer.insert(str);        }    }

UI層

public class ProviderActivity extends AppCompatActivity {        private EditText mEditText;        private DataLayer mDataLayer;        private BusinessLayer mBusinessLayer;        @Override        protected void onCreate(Bundle savedInstanceState){            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_provider);            initView();            findViewById(R.id.tv_submit).setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    String userInput = mEditText.getText().toString();                    if(!TextUtils.isEmpty(userInput)){                        mDataLayer = new DataLayerImpl(ProviderActivity01.this);                        mBusinessLayer = new BusinessLayerImpl(dataLayer);                        mBusinessLayer.check(userInput);                    }else{                        Toast.makeText(ProviderActivity01.this,"抱歉,你輸入的資料不合法",Toast.LENGTH_SHORT).show();                    }                }            });    }

資料層和業務層的解耦,通過介面和構造注入解決;在物件導向的世界裡,類與類之間可以有這麼幾種關係: 零耦合:表現在兩個類之間沒有任何耦合關係; 具體耦合:表現在一個類對另一個類的直接引用; 抽象耦合:表現在一個具體類和一個抽象類別之間;

那上面的虛擬碼還是主要體現在了抽象耦合,通過對業務層的建構函式傳入資料層的介面,這樣久使得依賴關係存在了最大的靈活性。最後,我們高層級的模組都依賴於抽象了(介面)。更進一步,我們的抽象不依賴於細節,它們也依賴於抽象。
總結上面的虛擬碼,UI 層是依賴於商務邏輯層的介面的,商務邏輯層的介面依賴於資料層的介面. 總結:依賴倒置原則的使用前提得看情境,其具體的體現是在抽象類別型上,不要為了抽象而去抽象,一些相對穩定、保持不變的類也沒有使用的必要. Ⅳ.總結…繼續…

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.