日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一个经典实例理解继承与多态原理与优点(附源码)---面向对象继承和多态性理解得不够深刻的同学请进...

發布時間:2023/11/30 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一个经典实例理解继承与多态原理与优点(附源码)---面向对象继承和多态性理解得不够深刻的同学请进... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一 引子

都說面向對象的4大支柱是抽象,封裝,繼承與多態。但是一些初涉編程的開發人員,體會不到繼承與多態的妙用,本文就試以一個經典實例來詮釋繼承與多態的用武之地。本實例的需求來自《重構》一書。

二 需求

1. 任務說明

?

我們的需求是一個影片出租的小應用,該應用會記錄每個顧客的消費金額并打印出來。
程序輸入為:顧客租的影片及對應的租期;
程序的處理為:根據顧客租用影片時間及影片類型,計算費用;輸出:打印消費單。
影片有三種類型:普通影片、兒童影片及新上映影片。
另外,模仿時下潮流,程序還提供了積分制度,為常客計算積分 ,積分會根據影片是否為新上映影片而不同。

?

租賃費用計算:

影片類型為兒童片,兩天以內費用為2,超出兩天的時間,每天的費用為1.5

影片類型為新片,每天的費用為3

影片類型為普通片,三天以內費用為1.5,超出三天,每天的費用為1.5

積分計算:

每次租賃影片,積分加一,如果影片為新片且租賃時間大于1天,則多加一分

2. 本實例為控制臺程序,運行界面如下:?

三 非繼承多態實現方式

根據需求,我們定義三個類,分別是movie類,Rental類(代表一條租用記錄)和Customer類(租碟顧客)

其中movie類的代碼如下:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace _1.cntbed 7 { 8 public enum TYPE 9 { 10 REGULAR, 11 NEW_RELEASE, 12 CHILDRENS 13 } 14 15 class Movie 16 { 17 private string _title; //movie name 18 TYPE _typeCode; //price code 19 20 public Movie() 21 { 22 _title = "unname"; 23 _typeCode = 0; 24 } 25 26 public Movie(string title, TYPE typeCode) 27 { 28 _title = title; 29 _typeCode = typeCode; 30 } 31 32 public TYPE getTypeCode() 33 { 34 return (TYPE)_typeCode; 35 } 36 37 void setTypeCode(TYPE arg) 38 { 39 _typeCode = arg; 40 } 41 42 public string getTitle() 43 { 44 return _title; 45 } 46 } 47 } View Code

Rental類的代碼如下,租用記錄中包含了一個movie對象,以及一個租期成員(積分和租金與此有關):

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {class Rental{private Movie _movie;int _daysRented;public Rental(Movie movie, int daysRented){_movie = movie;_daysRented = daysRented;}public int getDaysRented(){return _daysRented;}public Movie getMovie(){return _movie;}} } View Code

Customer類的代碼如下:

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {class Customer{private string _name;List<Rental> _rentals = new List<Rental>();public Customer(string name){_name = name;}public void addRental(Rental arg){_rentals.Add(arg);}string getName(){return _name;}public string statement(){double totalAmount = 0; //總共的租金int frequentRenterPoints = 0;//積分string result = "\r-------------------------------------------\n\r " +"租碟記錄--- " + getName() + "\n";foreach (Rental iter in _rentals){double thisAmount = 0;Rental each = iter;switch (each.getMovie().getTypeCode()){case TYPE.REGULAR:thisAmount += 2;//2天之內2元if (each.getDaysRented() > 2)thisAmount += (each.getDaysRented() - 2) * 1.5;break;case TYPE.NEW_RELEASE:thisAmount += each.getDaysRented() * 3;break;case TYPE.CHILDRENS:thisAmount += 1.5;//3天之內1.5元if (each.getDaysRented() > 3)thisAmount += (each.getDaysRented() - 3) * 1.5;break;}frequentRenterPoints++;//對于每一種類型的影片,一次租用積分加1if ((each.getMovie().getTypeCode() == TYPE.NEW_RELEASE) &&each.getDaysRented() > 1)frequentRenterPoints++;result += "\n\t" + each.getMovie().getTitle() + "\t" + thisAmount;totalAmount += thisAmount;}result += "\n共消費 " + totalAmount + "" + "\n您增加了 " + frequentRenterPoints + " 個積分\n";return result;}} } View Code

主程序代碼如下:

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {class Program{static void Main(string[] args){Console.Write("影碟店客戶租碟明細");Movie m1 = new Movie("致我們終將逝去的青春", TYPE.NEW_RELEASE);Movie m2 = new Movie("我是特種兵之利刃出鞘", TYPE.REGULAR);Movie m3 = new Movie("熊出沒之環球大冒險", TYPE.CHILDRENS);Rental r1 = new Rental(m1, 4);Rental r2 = new Rental(m1, 2);Rental r3 = new Rental(m3, 7);Rental r4 = new Rental(m2, 5);Rental r5 = new Rental(m3, 3);Customer c1 = new Customer("孫紅雷");c1.addRental(r1);c1.addRental(r4);Customer c2 = new Customer("林志玲");c2.addRental(r1);c2.addRental(r3);c2.addRental(r2);Customer c3 = new Customer("劉德華");c3.addRental(r3);c3.addRental(r5);Customer c4 = new Customer("孫儷");c4.addRental(r2);c4.addRental(r3);c4.addRental(r5);Console.Write(c1.statement());Console.Write(c2.statement());Console.Write(c3.statement());Console.Write(c4.statement());}} } View Code

四 繼承多態實現方式

我們定義一個Movie父類,每種影片類型均定義一個Movie子類(ChildrensMovie,NewReleaseMovie,RegularMovie),同時定義一個Movie工廠類(MovieFactoryMethod)。代碼如下:

新的Movie類的代碼如下:Movie類提供積分計算和租金計算的默認實現。

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {public enum TYPE{REGULAR,NEW_RELEASE,CHILDRENS}public class Movie{protected string _title; //movie nameTYPE _priceCode; //price codepublic Movie(){_title = "unname";_priceCode = 0;}public Movie(string title, TYPE priceCode){_title = title;_priceCode = priceCode;}public virtual double getCharge(int daysRented){return 0;//收費 }public virtual int getFrequentRenterPoints(int daysRented)//積分 {return 1;}public TYPE getPriceCode(){return (TYPE)_priceCode;}void setPriceCode(TYPE arg){_priceCode = arg;}public string getTitle(){return _title;}} } View Code

ChildrensMovie子類的代碼如下:重寫租金計算方法(多態性),積分計算方法從父類繼承。

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {public class ChildrensMovie : Movie{public ChildrensMovie (string title){_title = title;}public override double getCharge(int daysRented){double result = 1.5;if (daysRented > 3)result += (daysRented - 3) * 1.5;return result;}} } View Code

NewReleaseMovie子類的代碼如下:重寫租金計算方法(多態性)和積分計算方法(多態性)。

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {public class NewReleaseMovie:Movie{public NewReleaseMovie (string title){_title = title;}public override double getCharge(int daysRented){return daysRented * 3;}public override int getFrequentRenterPoints(int daysRented){return (daysRented > 1) ? 2 : 1;}} } View Code

RegularMovie子類的代碼如下:重寫租金計算方法(多態性),積分計算方法從父類繼承。

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {public class RegularMovie : Movie{public RegularMovie(string title){_title = title;}public override double getCharge(int daysRented){double result = 2;if (daysRented > 2)result += (daysRented - 2) * 1.5;return result;}} } View Code

Rental類的代碼保持不變:

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {class Rental{private Movie _movie;int _daysRented;public Rental(Movie movie, int daysRented){_movie = movie;_daysRented = daysRented;}public int getDaysRented(){return _daysRented;}public Movie getMovie(){return _movie;}} } View Code

MovieFactoryMethod類的代碼如下:根據不同的影片類型,返回相應的派生類對象,注意這里的函數的返回值是父類。

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {public class MovieFactoryMethod{public Movie MakeMovie(string strTitle, TYPE arg){switch (arg){case TYPE.REGULAR:return new RegularMovie(strTitle);case TYPE.CHILDRENS:return new ChildrensMovie(strTitle);case TYPE.NEW_RELEASE:return new NewReleaseMovie(strTitle);default://cout << "Incorrect Price Code" << endl;return null;}}} } View Code

新的Customer代碼如下:變得簡單了,不用關心List里的Movie類對象的真正類型,會自動調用相應派生類的方法

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {class Customer{private string _name;List<Rental> _rentals = new List<Rental>();public Customer(string name){_name = name;}public void addRental(Rental arg){_rentals.Add(arg);}string getName(){return _name;}public string statement(){double totalAmount = 0; //總共的租金int frequentRenterPoints = 0;//積分string result = "\r-------------------------------------------\n\r " +"租碟記錄--- " + getName() + "\n";foreach (Rental iter in _rentals){Rental each = iter;frequentRenterPoints += each.getMovie().getFrequentRenterPoints(each.getDaysRented());result += "\n\t" + each.getMovie().getTitle() + "\t" + each.getMovie().getCharge(each.getDaysRented());totalAmount += each.getMovie().getCharge(each.getDaysRented()); }result += "\n共消費 " + totalAmount + "" + "\n您增加了 " + frequentRenterPoints + " 個積分\n";return result;}} } View Code

最后,主程序的代碼如下:注意Rental類接受一個Movie類的參數,但是我們可以傳遞給他一個派生類對象。

using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace _1.cntbed {class Program{static void Main(string[] args){Console.Write("影碟店客戶租碟明細");MovieFactoryMethod mfm = new MovieFactoryMethod();Movie m1 = mfm.MakeMovie("致我們終將逝去的青春", TYPE.NEW_RELEASE);Movie m2 = mfm.MakeMovie("我是特種兵之利刃出鞘", TYPE.REGULAR);Movie m3 = mfm.MakeMovie("熊出沒之環球大冒險", TYPE.CHILDRENS);Rental r1 = new Rental(m1, 4);Rental r2 = new Rental(m1, 2);Rental r3 = new Rental(m3, 7);Rental r4 = new Rental(m2, 5);Rental r5 = new Rental(m3, 3);Customer c1 = new Customer("孫紅雷");c1.addRental(r1);c1.addRental(r4);Customer c2 = new Customer("林志玲");c2.addRental(r1);c2.addRental(r3);c2.addRental(r2);Customer c3 = new Customer("劉德華");c3.addRental(r3);c3.addRental(r5);Customer c4 = new Customer("孫儷");c4.addRental(r2);c4.addRental(r3);c4.addRental(r5);Console.Write(c1.statement());Console.Write(c2.statement());Console.Write(c3.statement());Console.Write(c4.statement());}} } View Code

五??總結

函數的返回值是父類,我們卻可以返回一個派生類對象;函數的參數是父類,我們卻可以傳入一個派生類對象。foreach循環遍歷List<>,程序會自動根據List里保存的對象的真正類型,引用相應的方法。

我們這個需求,無論租何種影片,租多長時間,都送一積分,故在Movie基類提供了積分計算方法getFrequentRenterPoints()的默認實現;NewReleaseMovie類型的影片積分計算方法有所不同,故重寫了getFrequentRenterPoints()方法;關于租金計算方法getCharge,大家可以試著自行分析。

考慮增加支持一種新影片類型-TVB電視劇:積分和租金的計算規則如下:

租金計算方式:借7天之內收5元,超過7天,之后每天收2元
積分:只要租了就積1分,然后每達到3天的倍數積1分(比如1-2天積1分,3-5天積2分)

要求在以上2個小框架中,分別實現該需求,然后,回過頭來看看,那種方式更加方便,就可以更好的體會到繼承和多態的強大之處了。

這里先揭示一下,在非繼承多態框架下,實現新增一種影片類型或現有影片類型的積分或租金計算規則改變了,Customer都需要進行改動;而在繼承多態框架下,實現新增一種影片類型或現有影片類型的積分或租金計算規則改變了,Customer無需任何改動。在繼承多態框架下,若要新增一種影片類型,則只需新增一個Movie派生類;現有影片類型的積分或租金計算規則改變了,則只需重寫相應派生類型的積分或租金計算函數。

最后說一句,大型項目中,Customer的維護者和Movie家族類的維護者有可能不是同一個人,這樣,需求的變更對于Customer的維護者來說是透明的,Customer的維護者可能都不知道何時增加了幾種影片類型。

六?源碼下載

?demo代碼

??

作者:宋波
出處:http://www.cnblogs.com/ice-river/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,日后必有一番作為!旁邊有“推薦”二字,你就順手把它點了吧,相得準,我分文不收;相不準,你也好回來找我!

轉載于:https://www.cnblogs.com/ice-river/p/3573735.html

總結

以上是生活随笔為你收集整理的一个经典实例理解继承与多态原理与优点(附源码)---面向对象继承和多态性理解得不够深刻的同学请进...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。