长沙正规网站建设价格,网站建设定金合同范本,南京公司官网设计,wordpress移动端文件一 引子 都说面向对象的4大支柱是抽象#xff0c;封装#xff0c;继承与多态。但是一些初涉编程的开发人员#xff0c;体会不到继承与多态的妙用#xff0c;本文就试以一个经典实例来诠释继承与多态的用武之地。本实例的需求来自《重构》一书。 二 需求 1. 任务说明 我们的…一 引子 都说面向对象的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.cntbed7 {8 public enum TYPE9 {
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;ListRental _rentals new ListRental();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子类ChildrensMovieNewReleaseMovieRegularMovie同时定义一个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;ListRental _rentals new ListRental();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