亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

解析Java實(shí)現(xiàn)設(shè)計(jì)模式六大原則之里氏替換原則

 更新時(shí)間:2021年06月23日 15:18:54   作者:盛開(kāi)的太陽(yáng)  
里氏替換原則是用來(lái)幫助我們?cè)诶^承關(guān)系中進(jìn)行父子類(lèi)的設(shè)計(jì)。它闡述了有關(guān)繼承的一些原則,也就是什么時(shí)候應(yīng)該使用繼承,什么時(shí)候不應(yīng)該使用繼承,以及其中蘊(yùn)含的原理。它是繼承復(fù)用的基礎(chǔ),反映了基類(lèi)與子類(lèi)之間的關(guān)系,是對(duì)開(kāi)閉原則的補(bǔ)充,對(duì)實(shí)現(xiàn)抽象化具體步驟的規(guī)范

一、什么是里氏替換原則

1.1、里氏替換原則定義

里氏替換原則(Liskov Substitution principle)是對(duì)子類(lèi)型的特別定義的. 為什么叫里氏替換原則呢?因?yàn)檫@項(xiàng)原則最早是在1988年,由麻省理工學(xué)院的一位姓里的女士(Barbara Liskov)提出來(lái)的。

里氏替換原則有兩層定義:

定義1

If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program。
如果S是T的子類(lèi),則T的對(duì)象可以替換為S的對(duì)象,而不會(huì)破壞程序。

定義2:

Functions that use pointers of references to base classes must be able to use objects of derived classes without knowing it。
所有引用其父類(lèi)對(duì)象方法的地方,都可以透明的替換為其子類(lèi)對(duì)象

這兩種定義方式其實(shí)都是一個(gè)意思,即:應(yīng)用程序中任何父類(lèi)對(duì)象出現(xiàn)的地方,我們都可以用其子類(lèi)的對(duì)象來(lái)替換,并且可以保證原有程序的邏輯行為和正確性。

1.2、里氏替換原則有至少有兩種含義

1.里氏替換原則是針對(duì)繼承而言的,如果繼承是為了實(shí)現(xiàn)代碼重用,也就是為了共享方法,那么共享的父類(lèi)方法就應(yīng)該保持不變,不能被子類(lèi)重新定義。子類(lèi)只能通過(guò)新添加方法來(lái)擴(kuò)展功能,父類(lèi)和子類(lèi)都可以實(shí)例化,而子類(lèi)繼承的方法和父類(lèi)是一樣的,父類(lèi)調(diào)用方法的地方,子類(lèi)也可以調(diào)用同一個(gè)繼承得來(lái)的,邏輯和父類(lèi)一致的方法,這時(shí)用子類(lèi)對(duì)象將父類(lèi)對(duì)象替換掉時(shí),當(dāng)然邏輯一致,相安無(wú)事。

2.如果繼承的目的是為了多態(tài),而多態(tài)的前提就是子類(lèi)覆蓋并重新定義父類(lèi)的方法,為了符合LSP,我們應(yīng)該將父類(lèi)定義為抽象類(lèi),并定義抽象方法,讓子類(lèi)重新定義這些方法,當(dāng)父類(lèi)是抽象類(lèi)時(shí),父類(lèi)就是不能實(shí)例化,所以也不存在可實(shí)例化的父類(lèi)對(duì)象在程序里。也就不存在子類(lèi)替換父類(lèi)實(shí)例(根本不存在父類(lèi)實(shí)例了)時(shí)邏輯不一致的可能。

不符合LSP的最常見(jiàn)的情況是,父類(lèi)和子類(lèi)都是可實(shí)例化的非抽象類(lèi),且父類(lèi)的方法被子類(lèi)重新定義,這一類(lèi)的實(shí)現(xiàn)繼承會(huì)造成父類(lèi)和子類(lèi)間的強(qiáng)耦合,也就是實(shí)際上并不相關(guān)的屬性和方法牽強(qiáng)附會(huì)在一起,不利于程序擴(kuò)展和維護(hù)。

二、使用里氏替換原則的目的

采用里氏替換原則就是為了減少繼承帶來(lái)的缺點(diǎn),增強(qiáng)程序的健壯性,版本升級(jí)時(shí)也可以保持良好的兼容性。即使增加子類(lèi),原有的子類(lèi)也可以繼續(xù)運(yùn)行。

三、里氏替換原則與繼承多態(tài)之間的關(guān)系

里氏替換原則和繼承多態(tài)有關(guān)系, 但是他倆并不是一回事. 我們來(lái)看看下面的案例

public class Cache {
    public void set(String key, String value) {

    }
}

public class Redis extends Cache {
    @Override
    public void set(String key, String value) {

    }
}


public class Memcache extends Cache {
    @Override
    public void set(String key, String value) {

    }
}

public class CacheTest {
    public static void main(String[] args) {
        // 父類(lèi)對(duì)象都可以接收子類(lèi)對(duì)象
        Cache cache = new Cache();
        cache.set("key123", "key123");

        cache = new Redis();
        cache.set("key123", "key123");

        cache = new Memcache();
        cache.set("key123", "key123");
    }
}

通過(guò)上面的例子, 可以看出Cache是父類(lèi), Redis 和 Memcache是子類(lèi), 他們繼承自Cache. 這是繼承和多態(tài)的思想. 而且這兩個(gè)子類(lèi)目前為止也都符合里氏替換原則.可以替換父類(lèi)出現(xiàn)的任何位置,并且原來(lái)代碼的邏輯行為不變且正確性也沒(méi)有被破壞。
看最后的CacheTest類(lèi), 我們使用父類(lèi)的cache可以接收任何一種類(lèi)型的緩存對(duì)象, 包括父類(lèi)和子類(lèi).

但如果我們對(duì)Redis中的set方法做了長(zhǎng)度校驗(yàn)

public class Redis extends Cache{
    @Override
    public void set(String key, String value) {
        if (key == null || key.length() < 10 || key.length() > 100) {
            System.out.println("key的長(zhǎng)度不符合要求");
            throw new IllegalArgumentException(key的長(zhǎng)度不符合要求);
        }
    }
}

public class CacheTest {
    public static void main(String[] args) {
        // 父類(lèi)對(duì)象都可以接收子類(lèi)對(duì)象
        Cache cache = new Cache();
        cache.set("key123", "key123");

        cache = new Redis();
        cache.set("key123", "key123");
    }
}

如上情況, 如果我們使用父類(lèi)對(duì)象時(shí)替換成子類(lèi)對(duì)象, 那么就會(huì)拋出異常. 程序的邏輯行為就發(fā)生了變化,雖然改造之后的代碼仍然可以通過(guò)子類(lèi)來(lái)替換父類(lèi) ,但是,從設(shè)計(jì)思路上來(lái)講,Redis子類(lèi)的設(shè)計(jì)是不符合里氏替換原則的。

繼承和多態(tài)是面向?qū)ο笳Z(yǔ)言所提供的一種語(yǔ)法,是代碼實(shí)現(xiàn)的思路,而里式替換則是一種思想,一種設(shè)計(jì)原則,是用來(lái)指導(dǎo)繼承關(guān)系中子類(lèi)該如何設(shè)計(jì)的,子類(lèi)的設(shè)計(jì)要保證在替換父類(lèi)的時(shí)候,不改變?cè)谐绦虻倪壿嬕约安黄茐脑谐绦虻恼_性。

四、里式替換的規(guī)則

里氏替換原則的核心就是“約定”,父類(lèi)與子類(lèi)的約定。里氏替換原則要求子類(lèi)在進(jìn)行設(shè)計(jì)的時(shí)候要遵守父類(lèi)的一些行為約定。這里的行為約定包括:函數(shù)所要實(shí)現(xiàn)的功能,對(duì)輸入、輸出、異常的約定,甚至包括注釋中一些特殊說(shuō)明等。

4.1、子類(lèi)方法不能違背父類(lèi)方法對(duì)輸入輸出異常的約定

1. 前置條件不能被加強(qiáng)

前置條件即輸入?yún)?shù)是不能被加強(qiáng)的,就像上面Cache的示例,Redis子類(lèi)對(duì)輸入?yún)?shù)Key的要求進(jìn)行了加強(qiáng),此時(shí)在調(diào)用處替換父類(lèi)對(duì)象為子類(lèi)對(duì)象就可能引發(fā)異常。

也就是說(shuō),子類(lèi)對(duì)輸入的數(shù)據(jù)的校驗(yàn)比父類(lèi)更加嚴(yán)格,那子類(lèi)的設(shè)計(jì)就違背了里氏替換原則。

2. 后置條件不能被削弱

后置條件即輸出,假設(shè)我們的父類(lèi)方法約定輸出參數(shù)要大于0,調(diào)用父類(lèi)方法的程序根據(jù)約定對(duì)輸出參數(shù)進(jìn)行了大于0的驗(yàn)證。而子類(lèi)在實(shí)現(xiàn)的時(shí)候卻輸出了小于等于0的值。此時(shí)子類(lèi)的涉及就違背了里氏替換原則

3. 不能違背對(duì)異常的約定

在父類(lèi)中,某個(gè)函數(shù)約定,只會(huì)拋出 ArgumentNullException 異常, 那子類(lèi)的設(shè)計(jì)實(shí)現(xiàn)中只允許拋出 ArgumentNullException 異常,任何其他異常的拋出,都會(huì)導(dǎo)致子類(lèi)違背里氏替換原則。

4.2、子類(lèi)方法不能違背父類(lèi)方法定義的功能

public class Product {
    private BigDecimal amount;
    private Calendar createTime;
 
    public BigDecimal getAmount() {
        return amount;
    }
    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }
 
    public Calendar getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Calendar createTime) {
        this.createTime = createTime;
    }
}
 
public class ProductSort extends Sort<Product> {
 
    public void sortByAmount(List<Product> list) {
        //根據(jù)時(shí)間進(jìn)行排序
        list.sort((h1, h2)->h1.getCreateTime().compareTo(h2.getCreateTime()));
    }
}

父類(lèi)中提供的 sortByAmount() 排序函數(shù),是按照金額從小到大來(lái)進(jìn)行排序的,而子類(lèi)重寫(xiě)這個(gè) sortByAmount() 排序函數(shù)之后,卻是是按照創(chuàng)建日期來(lái)進(jìn)行排序的。那子類(lèi)的設(shè)計(jì)就違背里氏替換原則。

實(shí)際上對(duì)于如何驗(yàn)證子類(lèi)設(shè)計(jì)是否符合里氏替換原則其實(shí)有一個(gè)小技巧,那就是你可以使用父類(lèi)的單測(cè)來(lái)運(yùn)行子類(lèi)的代碼,如果不可以正常運(yùn)行,那么你就要考慮一下自己的設(shè)計(jì)是否合理了!

4.3、子類(lèi)必須完全實(shí)現(xiàn)父類(lèi)的抽象方法

如果你設(shè)計(jì)的子類(lèi)不能完全實(shí)現(xiàn)父類(lèi)的抽象方法那么你的設(shè)計(jì)就不滿(mǎn)足里氏替換原則。

// 定義抽象類(lèi)槍
public abstract class AbstractGun{
    // 射擊
    public abstract void shoot();
    
    // sr
    public abstract void kill();
}

比如我們定義了一個(gè)抽象的槍類(lèi),可以射擊和sr。無(wú)論是步槍還是手槍都可以射擊和sr,我們可以定義子類(lèi)來(lái)繼承父類(lèi)

// 定義手槍?zhuān)綐專(zhuān)瑱C(jī)槍
public class Handgun extends AbstractGun{   
    public void shoot(){  
         // 手槍射擊
    }
    
    public void kill(){    
        // 手槍sr
    }
}
public class Rifle extends AbstractGun{
    public void shoot(){
         // 步槍射擊
    }
    
    public void kill(){    
         // 步槍sr
    }
}

但是如果我們?cè)谶@個(gè)繼承體系內(nèi)加入一個(gè)玩具槍?zhuān)蜁?huì)有問(wèn)題了,因?yàn)橥婢邩屩荒苌鋼簦荒躶r。但是很多人寫(xiě)代碼經(jīng)常會(huì)這么寫(xiě)。

public class ToyGun extends AbstractGun{
    public void shoot(){
        // 玩具槍射擊
    }
    
    public void kill(){ 
        // 因?yàn)橥婢邩尣荒躶r,就返回空,或者直接throw一個(gè)異常出去
        throw new Exception("我是個(gè)玩具槍?zhuān)@不驚喜,意不意外,刺不刺激?");
    }
}

這時(shí),我們?nèi)绻咽褂酶割?lèi)對(duì)象的地方替換為子類(lèi)對(duì)象,顯然是會(huì)有問(wèn)題的(士兵上戰(zhàn)場(chǎng)結(jié)果發(fā)現(xiàn)自己拿的是個(gè)玩具)。

而這種情況不僅僅不滿(mǎn)足里氏替換原則,也不滿(mǎn)足接口隔離原則,對(duì)于這種場(chǎng)景可以通過(guò) ** 接口隔離+委托** 的方式來(lái)解決。

五、里氏替換原則的作用

1.里氏替換原則是實(shí)現(xiàn)開(kāi)閉原則的重要方式之一。

2.它克服了繼承中重寫(xiě)父類(lèi)造成的可復(fù)用性變差的缺點(diǎn)。

3.它是動(dòng)作正確性的保證。即類(lèi)的擴(kuò)展不會(huì)給已有的系統(tǒng)引入新的錯(cuò)誤,降低了代碼出錯(cuò)的可能性。

4.加強(qiáng)程序的健壯性,同時(shí)變更時(shí)可以做到非常好的兼容性,提高程序的維護(hù)性、可擴(kuò)展性,降低需求變更時(shí)引入的風(fēng)險(xiǎn)。

盡量不要從可實(shí)例化的父類(lèi)中繼承,而是要使用基于抽象類(lèi)和接口的繼承。

六、里氏替換原則的實(shí)現(xiàn)方法

里氏替換原則通俗來(lái)講就是:子類(lèi)可以擴(kuò)展父類(lèi)的功能,但不能改變父類(lèi)原有的功能。也就是說(shuō):子類(lèi)繼承父類(lèi)時(shí),除添加新的方法完成新增功能外,盡量不要重寫(xiě)父類(lèi)的方法。

根據(jù)上述理解,對(duì)里氏替換原則的定義可以總結(jié)如下:

1.子類(lèi)可以實(shí)現(xiàn)父類(lèi)的抽象方法,但不能覆蓋父類(lèi)的非抽象方法

2.子類(lèi)中可以增加自己特有的方法

3.當(dāng)子類(lèi)的方法重載父類(lèi)的方法時(shí),方法的前置條件(即方法的輸入?yún)?shù))要比父類(lèi)的方法更寬松

4.當(dāng)子類(lèi)的方法實(shí)現(xiàn)父類(lèi)的方法時(shí)(重寫(xiě)/重載或?qū)崿F(xiàn)抽象方法),方法的后置條件(即方法的的輸出/返回值)要比父類(lèi)的方法更嚴(yán)格或相等

通過(guò)重寫(xiě)父類(lèi)的方法來(lái)完成新的功能寫(xiě)起來(lái)雖然簡(jiǎn)單,但是整個(gè)繼承體系的可復(fù)用性會(huì)比較差,特別是運(yùn)用多態(tài)比較頻繁時(shí),程序運(yùn)行出錯(cuò)的概率會(huì)非常大。

如果程序違背了里氏替換原則,則繼承類(lèi)的對(duì)象在基類(lèi)出現(xiàn)的地方會(huì)出現(xiàn)運(yùn)行錯(cuò)誤。這時(shí)其修正方法是:取消原來(lái)的繼承關(guān)系,重新設(shè)計(jì)它們之間的關(guān)系。

關(guān)于里氏替換原則的例子,最有名的是“正方形不是長(zhǎng)方形”。當(dāng)然,生活中也有很多類(lèi)似的例子,例如,企鵝、鴕鳥(niǎo)和幾維鳥(niǎo)從生物學(xué)的角度來(lái)劃分,它們屬于鳥(niǎo)類(lèi);但從類(lèi)的繼承關(guān)系來(lái)看,由于它們不能繼承“鳥(niǎo)”會(huì)飛的功能,所以它們不能定義成“鳥(niǎo)”的子類(lèi)。同樣,由于“氣球魚(yú)”不會(huì)游泳,所以不能定義成“魚(yú)”的子類(lèi);“玩具炮”炸不了敵人,所以不能定義成“炮”的子類(lèi)等。

七、案例分析

7.1、案例一: 兩數(shù)相減

當(dāng)使用繼承時(shí),遵循里氏替換原則。類(lèi)B繼承類(lèi)A時(shí),除添加新的方法完成新增功能P2外,盡量不要重寫(xiě)父類(lèi)A的方法,也盡量不要重載父類(lèi)A的方法。

繼承包含這樣一層含義:父類(lèi)中凡是已經(jīng)實(shí)現(xiàn)好的方法(相對(duì)于抽象方法而言),實(shí)際上是在設(shè)定一系列的規(guī)范和契約,雖然它不強(qiáng)制要求所有的子類(lèi)必須遵從這些契約,但是如果子類(lèi)對(duì)這些非抽象方法任意修改,就會(huì)對(duì)整個(gè)繼承體系造成破壞。而里氏替換原則就是表達(dá)了這一層含義。

繼承作為面向?qū)ο笕筇匦灾唬诮o程序設(shè)計(jì)帶來(lái)巨大便利的同時(shí),也帶來(lái)了弊端。比如使用繼承會(huì)給程序帶來(lái)侵入性,程序的可移植性降低,增加了對(duì)象間的耦合性,如果一個(gè)類(lèi)被其他的類(lèi)所繼承,則當(dāng)這個(gè)類(lèi)需要修改時(shí),必須考慮到所有的子類(lèi),并且父類(lèi)修改后,所有涉及到子類(lèi)的功能都有可能會(huì)產(chǎn)生故障。

class A{
	public int func1(int a, int b){
		return a-b;
	}
}
 
public class Client{
	public static void main(String[] args){
		A a = new A();
		System.out.println("100-50="+a.func1(100, 50));
		System.out.println("100-80="+a.func1(100, 80));
	}
}

運(yùn)行結(jié)果:

100-50=50
100-80=20

后來(lái),我們需要增加一個(gè)新的功能:完成兩數(shù)相加,然后再與100求和,由類(lèi)B來(lái)負(fù)責(zé)。即類(lèi)B需要完成兩個(gè)功能:

  • 兩數(shù)相減。
  • 兩數(shù)相加,然后再加100。

由于類(lèi)A已經(jīng)實(shí)現(xiàn)了第一個(gè)功能,所以類(lèi)B繼承類(lèi)A后,只需要再完成第二個(gè)功能就可以了,代碼如下:

class B extends A{
	public int func1(int a, int b){
		return a+b;
	}
	
	public int func2(int a, int b){
		return func1(a,b)+100;
	}
}
 
public class Client{
	public static void main(String[] args){
		B b = new B();
		System.out.println("100-50="+b.func1(100, 50));
		System.out.println("100-80="+b.func1(100, 80));
		System.out.println("100+20+100="+b.func2(100, 20));
	}
}

類(lèi)B完成后,運(yùn)行結(jié)果:

100-50=150
100-80=180
100+20+100=220

我們發(fā)現(xiàn)原本運(yùn)行正常的相減功能發(fā)生了錯(cuò)誤。原因就是類(lèi)B在給方法起名時(shí)無(wú)意中重寫(xiě)了父類(lèi)的方法,造成所有運(yùn)行相減功能的代碼全部調(diào)用了類(lèi)B重寫(xiě)后的方法,造成原本運(yùn)行正常的功能出現(xiàn)了錯(cuò)誤。在本例中,引用基類(lèi)A完成的功能,換成子類(lèi)B之后,發(fā)生了異常。在實(shí)際編程中,我們常常會(huì)通過(guò)重寫(xiě)父類(lèi)的方法來(lái)完成新的功能,這樣寫(xiě)起來(lái)雖然簡(jiǎn)單,但是整個(gè)繼承體系的可復(fù)用性會(huì)比較差,特別是運(yùn)用多態(tài)比較頻繁時(shí),程序運(yùn)行出錯(cuò)的幾率非常大。如果非要重寫(xiě)父類(lèi)的方法,比較通用的做法是:原來(lái)的父類(lèi)和子類(lèi)都繼承一個(gè)更通俗的基類(lèi),原有的繼承關(guān)系去掉,采用依賴(lài)、聚合,組合等關(guān)系代替。

7.2、案例二: "幾維鳥(niǎo)不是鳥(niǎo)"

需求分析: 鳥(niǎo)通常都是會(huì)飛的, 比如燕子每小時(shí)120千米, 但是新西蘭的幾維鳥(niǎo)由于翅膀退化不會(huì)飛. 假如要設(shè)計(jì)一個(gè)實(shí)例,計(jì)算這兩種鳥(niǎo)飛行 300 千米要花費(fèi)的時(shí)間。顯然,拿燕子來(lái)測(cè)試這段代碼,結(jié)果正確,能計(jì)算出所需要的時(shí)間;但拿幾維鳥(niǎo)來(lái)測(cè)試,結(jié)果會(huì)發(fā)生“除零異常”或是“無(wú)窮大”,明顯不符合預(yù)期,其類(lèi)圖如圖 1 所示。

源碼如下:

/**
 * 鳥(niǎo)
 */
public class Bird {
    // 飛行的速度
    private double flySpeed;

    public void setFlySpeed(double flySpeed) {
        this.flySpeed = flySpeed;
    }

    public double getFlyTime(double distance) {
        return distance/flySpeed;
    }
}

/**
 * 燕子
 */
public class Swallow extends Bird{
}

/**
 * 幾維鳥(niǎo)
 */
public class Kiwi extends Bird {
    @Override
    public void setFlySpeed(double flySpeed) {
        flySpeed = 0;
    }
}

/**
  * 測(cè)試飛行耗費(fèi)時(shí)間
  */
public class BirdTest {
    public static void main(String[] args) {
        Bird bird1 = new Swallow();
        Bird bird2 = new Kiwi();
        bird1.setFlySpeed(120);
        bird2.setFlySpeed(120);
        System.out.println("如果飛行300公里:");
        try {
            System.out.println("燕子花費(fèi)" + bird1.getFlyTime(300) + "小時(shí).");
            System.out.println("幾維花費(fèi)" + bird2.getFlyTime(300) + "小時(shí)。");
        } catch (Exception err) {
            System.out.println("發(fā)生錯(cuò)誤了!");
        }
    }
}

運(yùn)行結(jié)果:

如果飛行300公里:
燕子花費(fèi)2.5小時(shí).
幾維花費(fèi)Infinity小時(shí)。

程序運(yùn)行錯(cuò)誤的原因是:幾維鳥(niǎo)類(lèi)重寫(xiě)了鳥(niǎo)類(lèi)的 setSpeed(double speed) 方法,這違背了里氏替換原則。正確的做法是:取消幾維鳥(niǎo)原來(lái)的繼承關(guān)系,定義鳥(niǎo)和幾維鳥(niǎo)的更一般的父類(lèi),如動(dòng)物類(lèi),它們都有奔跑的能力。幾維鳥(niǎo)的飛行速度雖然為 0,但奔跑速度不為 0,可以計(jì)算出其奔跑 300 千米所要花費(fèi)的時(shí)間。其類(lèi)圖如圖 2 所示。

源代碼實(shí)現(xiàn)如下

/**
 * 動(dòng)物
 */
public class Animal {
    private double runSpeed;

    public double getRunTime(double distance) {
        return distance/runSpeed;
    }

    public void setRunSpeed(double runSpeed) {
        this.runSpeed = runSpeed;
    }
}


/**
 * 鳥(niǎo)
 */
public class Bird {
    // 飛行的速度
    private double flySpeed;

    public void setFlySpeed(double flySpeed) {
        this.flySpeed = flySpeed;
    }

    public double getFlyTime(double distance) {
        return distance/flySpeed;
    }
}

/**
 * 燕子
 */
public class Swallow extends Bird {
}

/**
 * 幾維鳥(niǎo)
 */
public class Kiwi extends Animal {
    @Override
    public void setRunSpeed(double runSpeed) {
        super.setRunSpeed(runSpeed);
    }
}

/**
  * 測(cè)試飛行耗費(fèi)時(shí)間
  */
public class BirdTest {
    public static void main(String[] args) {
        Bird bird1 = new Swallow();
        Animal bird2 = new Kiwi();
        bird1.setFlySpeed(120);
        bird2.setRunSpeed(110);
        System.out.println("如果飛行300公里:");
        try {
            System.out.println("燕子花費(fèi)" + bird1.getFlyTime(300) + "小時(shí).");
            System.out.println("幾維鳥(niǎo)花費(fèi)" + bird2.getRunTime(300) + "小時(shí)。");
        } catch (Exception err) {
            System.out.println("發(fā)生錯(cuò)誤了!");
        }
    }
}

運(yùn)行結(jié)果

如果飛行300公里:
燕子花費(fèi)2.5小時(shí).
幾維鳥(niǎo)花費(fèi)2.727272727272727小時(shí)。

八、總結(jié)

面向?qū)ο蟮木幊趟枷胫刑峁┝死^承和多態(tài)是我們可以很好的實(shí)現(xiàn)代碼的復(fù)用性和可擴(kuò)展性,但繼承并非沒(méi)有缺點(diǎn),因?yàn)槔^承的本身就是具有侵入性的,如果使用不當(dāng)就會(huì)大大增加代碼的耦合性,而降低代碼的靈活性,增加我們的維護(hù)成本,然而在實(shí)際使用過(guò)程中卻往往會(huì)出現(xiàn)濫用繼承的現(xiàn)象,而里氏替換原則可以很好的幫助我們?cè)诶^承關(guān)系中進(jìn)行父子類(lèi)的設(shè)計(jì)。

以上就是解析Java實(shí)現(xiàn)設(shè)計(jì)模式六大原則之里氏替換原則的詳細(xì)內(nèi)容,更多關(guān)于Java 設(shè)計(jì)模式 里氏替換原則的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java實(shí)戰(zhàn)入門(mén)之雙色球彩票小游戲

    Java實(shí)戰(zhàn)入門(mén)之雙色球彩票小游戲

    這篇文章主要介紹了Java實(shí)戰(zhàn)入門(mén)之雙色球彩票,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • 基于Java解析國(guó)密數(shù)字證書(shū)的操作方法

    基于Java解析國(guó)密數(shù)字證書(shū)的操作方法

    在Java環(huán)境中解析使用國(guó)密算法(如SM3WITHSM2)的數(shù)字證書(shū)可能遇到挑戰(zhàn),使用BouncyCastle加密庫(kù)可以解決Java標(biāo)準(zhǔn)庫(kù)無(wú)法識(shí)別國(guó)密算法橢圓曲線(xiàn)的問(wèn)題,成功解析國(guó)密數(shù)字證書(shū),添加BouncyCastle依賴(lài)并修改代碼,使其支持國(guó)密算法,即可解析采用SM3WITHSM2算法的數(shù)字證書(shū)
    2024-09-09
  • java實(shí)現(xiàn)簡(jiǎn)單的客戶(hù)信息管理系統(tǒng)

    java實(shí)現(xiàn)簡(jiǎn)單的客戶(hù)信息管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單的客戶(hù)信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 在eclipse中修改tomcat的部署路徑操作

    在eclipse中修改tomcat的部署路徑操作

    這篇文章主要介紹了在eclipse中修改tomcat的部署路徑操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01
  • SpringBoot的API文檔生成工具SpringDoc使用詳解

    SpringBoot的API文檔生成工具SpringDoc使用詳解

    這篇文章主要為大家介紹了SpringBoot的API文檔生成工具SpringDoc使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Springboot常用方法參數(shù)注解示例詳解

    Springboot常用方法參數(shù)注解示例詳解

    這篇文章主要介紹了Springboot常用方法參數(shù)注解及示例,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • Java基礎(chǔ)之動(dòng)態(tài)代理Cglib詳解

    Java基礎(chǔ)之動(dòng)態(tài)代理Cglib詳解

    這篇文章主要介紹了Java基礎(chǔ)之動(dòng)態(tài)代理Cglib詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05
  • SpringCloud gateway+zookeeper實(shí)現(xiàn)網(wǎng)關(guān)路由的詳細(xì)搭建

    SpringCloud gateway+zookeeper實(shí)現(xiàn)網(wǎng)關(guān)路由的詳細(xì)搭建

    這篇文章主要介紹了SpringCloud gateway+zookeeper實(shí)現(xiàn)網(wǎng)關(guān)路由,本文通過(guò)圖文實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • 如何使用ByteArrayOutputStream下載文件

    如何使用ByteArrayOutputStream下載文件

    這篇文章主要介紹了如何使用ByteArrayOutputStream下載文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 解決java 分割字符串成數(shù)組時(shí),小圓點(diǎn)不能直接進(jìn)行分割的問(wèn)題

    解決java 分割字符串成數(shù)組時(shí),小圓點(diǎn)不能直接進(jìn)行分割的問(wèn)題

    這篇文章主要介紹了解決java 分割字符串成數(shù)組時(shí),小圓點(diǎn)不能直接進(jìn)行分割的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12

最新評(píng)論