C# 多态相关的文章
一 C# 多態(tài)的實(shí)現(xiàn)
封裝、繼承、多態(tài),面向?qū)ο蟮娜筇匦?#xff0c;前兩項(xiàng)理解相對容易,但要理解多態(tài),特別是深入的了解,對于初學(xué)者而言可能就會(huì)有一定困難了。我一直認(rèn)為學(xué)習(xí)OO的最好方法就是結(jié)合實(shí)踐,封裝、繼承在實(shí)際工作中的應(yīng)用隨處可見,但多態(tài)呢?也許未必,可能不經(jīng)意間用到也不會(huì)把它跟“多態(tài)”這個(gè)詞對應(yīng)起來。在此拋磚引玉,大家討論,個(gè)人能力有限,不足之處還請指正。
之前看到過類似的問題:如果面試時(shí)主考官要求你用一句話來描述多態(tài),盡可能的精煉,你會(huì)怎么回答?當(dāng)然答案有很多,每個(gè)人的理解和表達(dá)不盡相同,但我比較趨向這樣描述:通過繼承實(shí)現(xiàn)的不同對象調(diào)用相同的方法,表現(xiàn)出不同的行為,稱之為多態(tài)。
例1:
代碼?
public class Animal{public virtual void Eat(){Console.WriteLine("Animal eat");}}public class Cat : Animal{public override void Eat(){Console.WriteLine("Cat eat");}}public class Dog : Animal{public override void Eat(){Console.WriteLine("Dog eat");}}class Tester{static void Main(string[] args){Animal[] animals = new Animal[3];animals[0] = new Animal();animals[1] = new Cat();animals[2] = new Dog();for (int i = 0; i < 3; i++){animals[i].Eat();}}}輸出如下:
Animal eat...
Cat eat...
Dog eat...
在上面的例子中,通過繼承,使得Animal對象數(shù)組中的不同的對象,在調(diào)用Eat()方法時(shí),表現(xiàn)出了不同的行為。
多態(tài)的實(shí)現(xiàn)看起來很簡單,要完全理解及靈活的運(yùn)用c#的多態(tài)機(jī)制,也不是一件容易的事,有很多需要注意的地方。
1. new的用法
先看下面的例子。
例2:
代碼?
public class Animal{public virtual void Eat(){Console.WriteLine("Animal eat");}}public class Cat : Animal{public new void Eat(){Console.WriteLine("Cat eat");}}class Tester{static void Main(string[] args){Animal a = new Animal();a.Eat();Animal ac = new Cat();ac.Eat();Cat c = new Cat();c.Eat();}}運(yùn)行結(jié)果為:
Animal eat...
Animal eat...
Cat eat...
可以看出,當(dāng)派生類Cat的Eat()方法使用new修飾時(shí),Cat的對象轉(zhuǎn)換為Animal對象后,調(diào)用的是Animal類中的Eat()方法。其實(shí)可以理解為,使用new關(guān)鍵字后,使得Cat中的Eat()方法和Animal中的Eat()方法成為毫不相關(guān)的兩個(gè)方法,只是它們的名字碰巧相同而已。所以, Animal類中的Eat()方法不管用還是不用virtual修飾,也不管訪問權(quán)限如何,或者是沒有,都不會(huì)對Cat的Eat()方法產(chǎn)生什么影響(只是因?yàn)槭褂昧薾ew關(guān)鍵字,如果Cat類沒用從Animal類繼承Eat()方法,編譯器會(huì)輸出警告)。
我想這是設(shè)計(jì)者有意這么設(shè)計(jì)的,因?yàn)橛袝r(shí)候我們就是要達(dá)到這種效果。嚴(yán)格的說,不能說通過使用new來實(shí)現(xiàn)多態(tài),只能說在某些特定的時(shí)候碰巧實(shí)現(xiàn)了多態(tài)的效果。
2.override實(shí)現(xiàn)多態(tài)
真正的多態(tài)使用override來實(shí)現(xiàn)的。回過去看前面的例1,在基類Animal中將方法Eat()用virtual標(biāo)記為虛擬方法,再在派生類Cat和Dog中用override對Eat()修飾,進(jìn)行重寫,很簡單就實(shí)現(xiàn)了多態(tài)。需要注意的是,要對一個(gè)類中一個(gè)方法用override修飾,該類必須從父類中繼承了一個(gè)對應(yīng)的用virtual修飾的虛擬方法,否則編譯器將報(bào)錯(cuò)。
好像講得差不多了,還有一個(gè)問題,不知道你想沒有。就是多層繼承中又是怎樣實(shí)現(xiàn)多態(tài)的。比如類A是基類,有一個(gè)虛擬方法method()(virtual修飾),類B繼承自類A,并對method()進(jìn)行重寫(override修飾),現(xiàn)在類C又繼承自類B,是不是可以繼續(xù)對method()進(jìn)行重寫,并實(shí)現(xiàn)多態(tài)呢?看下面的例子。
例3:
代碼?
public class Animal{public virtual void Eat(){Console.WriteLine("Animal eat");}}public class Dog : Animal{public override void Eat(){Console.WriteLine("Dog eat");}}public class WolfDog : Dog{public override void Eat(){Console.WriteLine("WolfDog eat");}}class Tester{static void Main(string[] args){Animal[] animals = new Animal[3];animals[0] = new Animal();animals[1] = new Dog();animals[2] = new WolfDog();for (int i = 0; i < 3; i++){animals[i].Eat();}} }?運(yùn)行結(jié)果為:
Animal eat...
Dog eat...
WolfDog eat...?
在上面的例子中類Dog繼承自類Animal,對方法Eat()進(jìn)行了重寫,類WolfDog又繼承自Dog,再一次對Eat()方法進(jìn)行了重寫,并很好地實(shí)現(xiàn)了多態(tài)。不管繼承了多少層,都可以在子類中對父類中已經(jīng)重寫的方法繼續(xù)進(jìn)行重寫,即如果父類方法用override修飾,如果子類繼承了該方法,也可以用override修飾,多層繼承中的多態(tài)就是這樣實(shí)現(xiàn)的。要想終止這種重寫,只需重寫方法時(shí)用sealed關(guān)鍵字進(jìn)行修飾即可。
3. abstract-override實(shí)現(xiàn)多態(tài)
先在我們在來討論一下用abstract修飾的抽象方法。抽象方法只是對方法進(jìn)行了定義,而沒有實(shí)現(xiàn),如果一個(gè)類包含了抽象方法,那么該類也必須用abstract聲明為抽象類,一個(gè)抽象類是不能被實(shí)例化的。對于類中的抽象方法,可以再其派生類中用override進(jìn)行重寫,如果不重寫,其派生類也要被聲明為抽象類。看下面的例子。
例4:
代碼?
public abstract class Animal{public abstract void Eat();}public class Cat : Animal{public override void Eat(){Console.WriteLine("Cat eat");}}public class Dog : Animal{public override void Eat(){Console.WriteLine("Dog eat");}}public class WolfDog : Dog{public override void Eat(){Console.WriteLine("Wolfdog eat");}}class Tester{static void Main(string[] args){Animal[] animals = new Animal[3];animals[0] = new Cat();animals[1] = new Dog();animals[2] = new WolfDog();for (int i = 0; i < animals.Length; i++){animals[i].Eat();}}}運(yùn)行結(jié)果為:
Cat eat...
Dog eat...
Wolfdog eat...
從上面可以看出,通過使用abstract-override可以和virtual-override一樣地實(shí)現(xiàn)多態(tài),包括多層繼承也是一樣的。不同之處在于,包含虛擬方法的類可以被實(shí)例化,而包含抽象方法的類不能被實(shí)例化。
?
二 淺談C#多態(tài)的法力
前言:我們都知道面向?qū)ο蟮娜筇匦?#xff1a;封裝,繼承,多態(tài)。封裝和繼承對于初學(xué)者而言比較好理解,但要理解多態(tài),尤其是深入理解,初學(xué)者往往存在有很多困惑,為什么這樣就可以?有時(shí)候感覺很不可思議,由此,面向?qū)ο蟮镊攘w現(xiàn)了出來,那就是多態(tài),多態(tài)用的好,可以提高程序的擴(kuò)展性。常用的設(shè)計(jì)模式,比如簡單工廠設(shè)計(jì)模式,核心就是多態(tài)。
其實(shí)多態(tài)就是:允許將子類類型的指針賦值給父類類型的指針。也就是同一操作作用于不同的對象,可以有不同的解釋,產(chǎn)生不同的執(zhí)行結(jié)果。在運(yùn)行時(shí),可以通過指向基類的指針,來調(diào)用實(shí)現(xiàn)派生類中的方法。如果這邊不理解可以先放一放,先看下面的事例,看完之后再來理解這句話,就很容易懂了。
理解多態(tài)之前首先要對面向?qū)ο蟮睦锸咸鎿Q原則和開放封閉原則有所了解。
里氏替換原則(Liskov Substitution Principle):派生類(子類)對象能夠替換其基類(超類)對象被使用。通俗一點(diǎn)的理解就是“子類是父類”,舉個(gè)例子,“男人是人,人不一定是男人”,當(dāng)需要一個(gè)父類類型的對象的時(shí)候可以給一個(gè)子類類型的對象;當(dāng)需要一個(gè)子類類型對象的時(shí)候給一個(gè)父類類型對象是不可以的!
開放封閉原則(Open Closed Principle):封裝變化、降低耦合,軟件實(shí)體應(yīng)該是可擴(kuò)展,而不可修改的。也就是說,對擴(kuò)展是開放的,而對修改是封閉的。因此,開放封閉原則主要體現(xiàn)在兩個(gè)方面:對擴(kuò)展開放,意味著有新的需求或變化時(shí),可以對現(xiàn)有代碼進(jìn)行擴(kuò)展,以適應(yīng)新的情況。對修改封閉,意味著類一旦設(shè)計(jì)完成,就可以獨(dú)立完成其工作,而不要對類進(jìn)行任何修改。
對這兩個(gè)原則有一定了解之后就能更好的理解多態(tài)。
首先,我們先來看下怎樣用虛方法實(shí)現(xiàn)多態(tài)
我們都知道,喜鵲(Magpie)、老鷹(Eagle)、企鵝(Penguin)都是屬于鳥類,我們可以根據(jù)這三者的共有特性提取出鳥類(Bird)做為父類,喜鵲喜歡吃蟲子,老鷹喜歡吃肉,企鵝喜歡吃魚。
創(chuàng)建基類Bird如下,添加一個(gè)虛方法Eat():
/// <summary>/// 鳥類:父類/// </summary>public class Bird{/// <summary>/// 吃:虛方法/// </summary>public virtual void Eat(){Console.WriteLine("我是一只小小鳥,我喜歡吃蟲子~");}}創(chuàng)建子類Magpie如下,繼承父類Bird,重寫父類Bird中的虛方法Eat():
/// <summary>/// 喜鵲:子類/// </summary>public class Magpie:Bird{/// <summary>/// 重寫父類中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只喜鵲,我喜歡吃蟲子~");}}創(chuàng)建一個(gè)子類Eagle如下,繼承父類Bird,重寫父類Bird中的虛方法Eat():
/// <summary>/// 老鷹:子類/// </summary>public class Eagle:Bird{/// <summary>/// 重寫父類中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只老鷹,我喜歡吃肉~");}}創(chuàng)建一個(gè)子類Penguin如下,繼承父類Bird,重寫父類Bird中的虛方法Eat():
/// <summary>/// 企鵝:子類/// </summary>public class Penguin:Bird{/// <summary>/// 重寫父類中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只小企鵝,我喜歡吃魚~");}}到此,一個(gè)基類,三個(gè)子類已經(jīng)創(chuàng)建完畢,接下來我們在主函數(shù)中來看下多態(tài)是怎樣體現(xiàn)的。
static void Main(string[] args){//創(chuàng)建一個(gè)Bird基類數(shù)組,添加基類Bird對象,Magpie對象,Eagle對象,Penguin對象Bird[] birds = { new Bird(),new Magpie(),new Eagle(),new Penguin()};//遍歷一下birds數(shù)組foreach (Bird bird in birds){bird.Eat();}Console.ReadKey();}運(yùn)行結(jié)果:
由此可見,子類Magpie,Eagle,Penguin對象可以賦值給父類對象,也就是說父類類型指針可以指向子類類型對象,這里體現(xiàn)了里氏替換原則。
父類對象調(diào)用自己的Eat()方法,實(shí)際上顯示的是父類類型指針指向的子類類型對象重寫父類Eat后的方法。這就是多態(tài)。
多態(tài)的作用到底是什么呢?
其實(shí)多態(tài)的作用就是把不同的子類對象都當(dāng)作父類來看,可以屏蔽不同子類對象之間的差異,寫出通用的代碼,做出通用的編程,以適應(yīng)需求的不斷變化。
以上程序也體現(xiàn)了開放封閉原則,如果后面的同事需要擴(kuò)展我這個(gè)程序,還想再添加一個(gè)貓頭鷹(Owl),很容易,只需要添加一個(gè)Owl類文件,繼承Bird,重寫Eat()方法,添加給父類對象就可以了。至此,該程序的擴(kuò)展性得到了提升,而又不需要查看源代碼是如何實(shí)現(xiàn)的就可以擴(kuò)展新功能。這就是多態(tài)帶來的好處。
我們再來看下利用抽象如何來實(shí)現(xiàn)多態(tài)
還是剛才的例子,我們發(fā)現(xiàn)Bird這個(gè)父類,我們根本不需要使用它創(chuàng)建的對象,它存在的意義就是供子類來繼承。所以我們可以用抽象類來優(yōu)化它。
我們把Bird父類改成抽象類,Eat()方法改成抽象方法。代碼如下:
抽象類Bird內(nèi)添加一個(gè)Eat()抽象方法,沒有方法體。也不能實(shí)例化。
其他類Magpie,Eagle,Penguin代碼不變,子類也是用override關(guān)鍵字來重寫父類中抽象方法。
Main主函數(shù)中Bird就不能創(chuàng)建對象了,代碼稍微修改如下:
執(zhí)行結(jié)果:
由此可見,我們選擇使用虛方法實(shí)現(xiàn)多態(tài)還是抽象類抽象方法實(shí)現(xiàn)多態(tài),取決于我們是否需要使用基類實(shí)例化的對象.
比如說 現(xiàn)在有一個(gè)Employee類作為基類,ProjectManager類繼承自Employee,這個(gè)時(shí)候我們就需要使用虛方法來實(shí)現(xiàn)多態(tài)了,因?yàn)槲覀円褂肊mployee創(chuàng)建的對象,這些對象就是普通員工對象。
再比如說 現(xiàn)在有一個(gè)Person類作為基類,Student,Teacher 類繼承Person,我們需要使用的是Student和Teacher創(chuàng)建的對象,根本不需要使用Person創(chuàng)建的對象,
所以在這里Person完全可以寫成抽象類。
總而言之,是使用虛方法,或者抽象類抽象方法實(shí)現(xiàn)多態(tài),視情況而定,什么情況?以上我說的兩點(diǎn)~
接下來~~~~
我要問一個(gè)問題,喜鵲和老鷹都可以飛,這個(gè)飛的能力,我怎么來實(shí)現(xiàn)呢?
XXX答:“在父類Bird中添加一個(gè)Fly方法不就好了~~”
我再問:“好的,照你說的,企鵝繼承父類Bird,但是不能企鵝不能飛啊,這樣在父類Bird中添加Fly方法是不是不合適呢?”
XXX答:“那就在能飛的鳥類中分別添加Fly方法不就可以了嗎?”
對,這樣是可以,功能完全可以實(shí)現(xiàn),可是這樣違背了面向?qū)ο箝_放封閉原則,下次我要再擴(kuò)展一個(gè)鳥類比如貓頭鷹(Owl),我還要去源代碼中看下Fly是怎么實(shí)現(xiàn)的,然后在Owl中再次添加Fly方法,相同的功能,重復(fù)的代碼,這樣是不合理的,程序也不便于擴(kuò)展;
其次,如果我還要添加一個(gè)飛機(jī)類(Plane),我繼承Bird父類,合適嗎?
很顯然,不合適!所以我們需要一種規(guī)則,那就是接口了,喜鵲,老鷹,飛機(jī),我都實(shí)現(xiàn)這個(gè)接口,那就可以飛了,而企鵝我不實(shí)現(xiàn)這個(gè)接口,它就不能飛~~
好,接下來介紹一下接口如何實(shí)現(xiàn)多態(tài)~
添加一個(gè)接口IFlyable,代碼如下:
/// <summary>/// 飛 接口/// </summary>public interface IFlyable{void Fly();}喜鵲Magpie實(shí)現(xiàn)IFlyable接口,代碼如下:
/// <summary>/// 喜鵲:子類,實(shí)現(xiàn)IFlyable接口/// </summary>public class Magpie:Bird,IFlyable{/// <summary>/// 重寫父類Bird中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只喜鵲,我喜歡吃蟲子~");}/// <summary>/// 實(shí)現(xiàn) IFlyable接口方法/// </summary>public void Fly(){Console.WriteLine("我是一只喜鵲,我可以飛哦~~");}}老鷹Eagle實(shí)現(xiàn)IFlyable接口,代碼如下:
/// <summary>/// 老鷹:子類實(shí)現(xiàn)飛接口/// </summary>public class Eagle:Bird,IFlyable{/// <summary>/// 重寫父類Bird中Eat方法/// </summary>public override void Eat(){Console.WriteLine("我是一只老鷹,我喜歡吃肉~");}/// <summary>/// 實(shí)現(xiàn) IFlyable接口方法/// </summary>public void Fly(){Console.WriteLine("我是一只老鷹,我可以飛哦~~");}}在Main主函數(shù)中,創(chuàng)建一個(gè)IFlyable接口數(shù)組,代碼實(shí)現(xiàn)如下:
static void Main(string[] args){//創(chuàng)建一個(gè)IFlyable接口數(shù)組,添加 Magpie對象,Eagle對象IFlyable[] flys = { new Magpie(),new Eagle()};//遍歷一下flys數(shù)組foreach (IFlyable fly in flys){fly.Fly();}Console.ReadKey();}執(zhí)行結(jié)果:
由于企鵝Penguin沒有實(shí)現(xiàn)IFlyable接口,所以企鵝不能對象不能賦值給IFlyable接口對象,所以企鵝,不能飛~
好了,剛才我提到了飛機(jī)也能飛,繼承Bird不合適的問題,現(xiàn)在有了接口,這個(gè)問題也可以解決了。如下,我添加一個(gè)飛機(jī)Plane類,實(shí)現(xiàn)IFlyable接口,代碼如下:
/// <summary>/// 飛機(jī)類,實(shí)現(xiàn)IFlyable接口/// </summary>public class Plane:IFlyable{/// <summary>/// 實(shí)現(xiàn)接口方法/// </summary>public void Fly(){Console.WriteLine("我是一架飛機(jī),我也能飛~~");}}在Main主函數(shù)中,接口IFlyable數(shù)組,添加Plane對象:
class Program{static void Main(string[] args){//創(chuàng)建一個(gè)IFlyable接口數(shù)組,添加 Magpie對象,Eagle對象,Plane對象IFlyable[] flys = { new Magpie(),new Eagle(),new Plane()};//遍歷一下flys數(shù)組foreach (IFlyable fly in flys){fly.Fly();}Console.ReadKey();}}執(zhí)行結(jié)果:
由此,可以看出用接口實(shí)現(xiàn)多態(tài)程序的擴(kuò)展性得到了大大提升,以后不管是再擴(kuò)展一個(gè)蝴蝶(Butterfly),還是鳥人(Birder)創(chuàng)建一個(gè)類,實(shí)現(xiàn)這個(gè)接口,在主函數(shù)中添加該對象就可以了。
也不需要查看源代碼是如何實(shí)現(xiàn)的,體現(xiàn)了開放封閉原則!
接口充分體現(xiàn)了多態(tài)的魅力~~
?
以上通過一些小的事例,給大家介紹了面向?qū)ο笾腥N實(shí)現(xiàn)多態(tài)的方式,或許有人會(huì)問,在項(xiàng)目中怎么使用多態(tài)呢?多態(tài)的魅力在項(xiàng)目中如何體現(xiàn)?
那么接下來我做一個(gè)面向?qū)ο蟮暮唵斡?jì)算器,來Show一下多態(tài)在項(xiàng)目中使用吧!
加減乘除運(yùn)算,我們可以根據(jù)共性提取出一個(gè)計(jì)算類,里面包含兩個(gè)屬性 Number1和Number2,還有一個(gè)抽象方法Compute();代碼如下:
/// <summary>/// 計(jì)算父類/// </summary>public abstract class Calculate{public int Number1{get;set;}public int Number2{get;set;}public abstract int Compute();}接下來,我們添加一個(gè)加法器,繼承計(jì)算Calculate父類:
/// <summary>/// 加法器/// </summary>public class Addition : Calculate{/// <summary>/// 實(shí)現(xiàn)父類計(jì)算方法/// </summary>/// <returns>加法計(jì)算結(jié)果</returns>public override int Compute(){return Number1 + Number2;}}再添加一個(gè)減法器,繼承計(jì)算Calculate父類:
/// <summary>/// 減法器/// </summary>public class Subtraction : Calculate{/// <summary>/// 實(shí)現(xiàn)父類計(jì)算方法/// </summary>/// <returns>減法計(jì)算結(jié)果</returns>public override int Compute(){return Number1 - Number2;}}在主窗體FormMain中,編寫計(jì)算事件btn_Compute_Click,代碼如下:
private void btn_Compute_Click(object sender, EventArgs e){//獲取兩個(gè)參數(shù)int number1 = Convert.ToInt32(this.txt_Number1.Text.Trim());int number2 = Convert.ToInt32(this.txt_Number2.Text.Trim());//獲取運(yùn)算符string operation = cbb_Operator.Text.Trim();//通過運(yùn)算符,返回父類類型Calculate calculate = GetCalculateResult(operation);calculate.Number1 = number1;calculate.Number2 = number2;//利用多態(tài),返回運(yùn)算結(jié)果string result = calculate.Compute().ToString();this.lab_Result.Text = result;}/// <summary>/// 通過運(yùn)算符,返回父類類型/// </summary>/// <param name="operation"></param>/// <returns></returns>private Calculate GetCalculateResult(string operation){Calculate calculate = null;switch (operation){case "+":calculate = new Addition();break;case "-":calculate = new Subtraction();break;}return calculate;}在該事件中主要調(diào)用GetCalculateResult方法,通過運(yùn)算符,創(chuàng)建一個(gè)對應(yīng)的加減乘除計(jì)算器子類,然后賦值給父類,其實(shí)這就是設(shè)計(jì)模式中的簡單工廠設(shè)計(jì)模式,我給你一個(gè)運(yùn)算符你給我生產(chǎn)一個(gè)對應(yīng)的加減乘除計(jì)算器子類,返回給我。。其實(shí)大多數(shù)的設(shè)計(jì)模式的核心就是多態(tài),掌握好多態(tài),設(shè)計(jì)模式看起來也很輕松。
現(xiàn)階段工作已經(jīng)完成,但是過了一段時(shí)間,又添加新的需求了,我還要擴(kuò)展一個(gè)乘法了,那好,很簡單只要?jiǎng)?chuàng)建一個(gè)乘法計(jì)算器繼承Calculate父類即可,看代碼:
/// <summary>/// 乘法計(jì)算器/// </summary>public class Multiplication:Calculate{public override int Compute(){return Number1*Number2;}}然后在GetCalculateResult函數(shù)中添加一個(gè)case 就好了:
switch (operation){case "+":calculate = new Addition();break;case "-":calculate = new Subtraction();break;case "*":calculate = new Multiplication();break;}執(zhí)行結(jié)果:
好了,就這么方便,一個(gè)新的功能就擴(kuò)展完畢了,我根本不需要查看源代碼是如何實(shí)現(xiàn)的,這就是多態(tài)的好處!
多態(tài)性意味著有多重形式。在面向?qū)ο缶幊谭妒街?#xff0c;多態(tài)性往往表現(xiàn)為"一個(gè)接口,多個(gè)功能"。
多態(tài)性可以是靜態(tài)的或動(dòng)態(tài)的。在靜態(tài)多態(tài)性中,函數(shù)的響應(yīng)是在編譯時(shí)發(fā)生的。在動(dòng)態(tài)多態(tài)性中,函數(shù)的響應(yīng)是在運(yùn)行時(shí)發(fā)生的。
?
三 抽象和接口
什么時(shí)候用接口什么時(shí)候用抽象?
抽象:是對相同屬性和方法的提煉而得
接口:是對相同行為不同實(shí)現(xiàn)方法的提煉
如:? 每種支付方式 支付之前都需要校驗(yàn)一下支付金額是不是真確的,不能小于等于0 。因?yàn)樾r?yàn)方式,校驗(yàn)代碼都是一樣的,所以我們可以定義一個(gè) 抽象類給抽象出來.
public abstract class AbstractPayWay implements PayWay{private Double money;private boolean verify(){return money != null && money > 0; }/*** 這里實(shí)現(xiàn)了 PayWay 中的 pay 接口 方法 所以 AbstractPayWay 的子類 無需 實(shí)現(xiàn)該 方法,* 只需要 實(shí)現(xiàn) doPay() 方法,并且 如果 doPay()方法被成功調(diào)用則說明肯定 校驗(yàn)成功了。*/@Overridepublic boolean pay(){boolean verify = this.verify();if(!verify){System.out.println("支付金額驗(yàn)證錯(cuò)誤!");return false;}return this.doPay();}public abstract boolean doPay(); }所以 ?WeixinPayWay ?ZhifubaoPayWay 支付的具體實(shí)現(xiàn)類可以改改為?
/*** 繼承 AbstractPayWay 所以無需 寫公共的校驗(yàn)邏輯,直接寫支付業(yè)務(wù)邏輯* @author cyy*/ public class WeixinPayWay extends AbstractPayWay{@Overridepublic boolean doPay() {System.out.println("這里無需校驗(yàn)支付金額,直接調(diào)用支付方法就行");System.out.println("微信支付成功");return false;}}public class ZhifubaoPayWay extends AbstractPayWay{@Overridepublic boolean doPay() {System.out.println("這里無需校驗(yàn)支付金額,直接調(diào)用支付方法就行");System.out.println("支付寶支付成功");return false;}}?
?
?
參考:
https://www.cnblogs.com/wl-blog/p/10361894.html
https://blog.csdn.net/wab719591157/article/details/73741919
https://blog.csdn.net/u012135077/article/details/48286837
https://blog.csdn.net/u013538542/article/details/45365019
?
?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的C# 多态相关的文章的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unity Fine Prued Til
- 下一篇: C#委托(delegate、Action