深入继承之抽象类和接口综合分析及完整案列解说(二)

      通过深入继承之抽象类和接口综合分析及完整案列解说(一),我想大家已经认识到了知识共享的巨大力量了。我门上面看到的这些东西不是我们任何一个人在短时间内就能够总结出来的,但是大家一起总结,那结果就是这样爽的。

      我希望大家都能够大方一点,别做得那么小气,生怕自己知道的那点知识被别人知道了。饭碗就被别人抢了,事实上在跟人分享的过程中并不是一味的在付出,你同样也会有收获,无论是帮别人解答疑问还是跟别人交流,就好象我在写(或着说我是在复制别人的心得)一样,看起来我是在无偿的为大家做,事实上呢我同样的有收获的,因为写这个文章的时候我发现了很多我过去学和用中一之没有注意到的死角,也发现很多更新,更好的技巧。

      所以我相信,只要我门每个人都尽量的多跟人分享你所学,最终带来的是大家的共同进步。在园里我特别喜欢老赵(MSDN Web Cast的ASP.NET AJAX深入浅出系列课程),Dflying Chen(AJAX系列书籍),张逸老师(软件设计精要与模式,WCF),李会军(新版设计模式)等同志,他门的书籍及文章我相信大家看后都会受益非浅,他们在园里的排名及贡献是大家共同看到的。
      也许大家发现了我上面给张逸叫老师,这是为什么呢?上面列举的这些牛人中我就认识张逸,认识我的朋友可别说是我和他同姓才特别介绍,其实并不是这样。在我的学习过程中张逸老师对我帮助很大,在我大学即将毕业的最后一年里,我在张老师所在的公司实习(他当时是我门.NET开发一部的部长,管人可严了,我悄悄说的,大家看到了这句话一定是眼花了,呵呵),他曾经给我上很多课程和开过很多技术专题讲座,我想大家都知道,对于一个没毕业的大学生来说,没有一定的项目开发经验在写论文的时候是很吃力的,在我考系统分析师期间论文得到他的指导让我考试顺利通过,在此我借园子的位置想张老师说声谢谢。另外他所著的《软件设计精要与模式》对我的帮助也很大,虽然这不是一本讲解设计模式的专题书籍,他的写作却是以设计模式为主来讲解的,最后以MS开源项目PetShop 4.0作为案例讲解模式的应用,个人觉得写得很不错,我在现在的项目中都采用了书里的很多设计思想。

      看到这里大家是不是觉得我这个人很罗嗦了,写文章写到去介绍牛人和书籍去了,这是不是在为他门打广告????
好了,言归正转,我门还是进入主题,戏不能唱一半就停止了吧,既然开始了那么演得在差也得演唱完毕吧。看看下面这个实例:

      我门根据一个小书店的情况来说这个实例,当然实例不能准确的说明一切,只是说通过这个类让大家更感性的认识到抽象类和接口的使用情况。
首先分析书店的经营情况
    1. 书是可以出祖和销售的
    2. 书的分类为三个方面,所以销售和出祖的价格分别也分三个档次
    3. 顾客分为会员和普通顾客
    通过上面的分析,我们可以开始构思程序的实现了
    1. 无论买那种折扣的书都需要支付书对应的现金购买
    2. 无论租那种书都需要支付对应的租金
    3. 无论那种业务类型都需要返回出详细信息(实际上应该是写入数据库)
    4. 无论他的逻辑是怎么样的,我们在前台处理的时候并不想也不需要知道那么多,我们就希望用我们现在知道的信息直
        接换取到应该的操作.

    这两个我们使用接口来定义返回的 钱 .
    然后再定义一个接口方法来处理我们的写入数据库操作(这里是返回出详细信息)
    接下来把顾客类型,交易类型,书的类型以及租借类型(指是租书还是还书)分别做个枚举

    先来看一个UML图,我相信比我用手敲键盘更容易说清楚结构。


 一. 定义枚举及Money接口

 1namespace EBook
 2{
 3    /// <summary>
 4    /// 会员类型
 5    /// </summary>

 6    public enum U_Type
 7    {
 8        member,     //会员
 9        shopper,    //零售\租顾客
10    }

11    /// <summary>
12    /// 书的类型
13    /// </summary>

14    public enum B_Type
15    {
16        novel,      //小说
17        life,       //生活类
18        magazine    //杂志
19    }

20    /// <summary>
21    /// 交易类型
22    /// </summary>

23    public enum S_Type
24    {
25        sell,       //出售
26        hire        //出租
27    }

28    /// <summary>
29    /// 租借类型,租借,归还
30    /// </summary>

31    public enum H_Type
32    
33        rent,
34        back
35    }

36    /// <summary>
37    /// 定义一个接口,返回本次交易的钱
38    /// 执行最后插入数据库的操作
39    /// </summary>

40    public interface Money
41    {
42        double GetMoney();
43        string Execute();
44    }

45}

二. 实现借口,抽象出具体的逻辑方法,定义枚举及内部成员

namespace EBook
{
    
/// <summary>
    
/// 实现接口中返回钱的方法,并且定义一系列下面类都会用到的成员
    
/// 做为接口下的一个总承
    
/// </summary>

    public abstract class Root : Money
    
{
        
protected U_Type _utype;    //会员类型
        protected B_Type _btype;    //书的类型
        protected S_Type _stype;    //交易类型
        protected string _bookname; //书名
        protected string _uname;    //用户名
        protected double _price;    //书的定价
        protected double _cash;     //实际支付的现金,不管是租书还是还书还是买书,他都会涉及到最终给了多少钱这个问题

        
public abstract double GetMoney();
        
public abstract string Execute();
    }

    
/// <summary>
    
/// 作为销售类的一个基类,这个类实际上并没有做什么工作,主要是针对接口和基类做了一些补充说明
    
/// </summary>

    public abstract class Sell : Root
    
{
        
/// <summary>
        
/// 初始化该类
        
/// </summary>  
        
/// <param name="un">用户名</param>
        
/// <param name="bn">书名</param>
        
/// <param name="p">书的定价</param>

        public Sell(string un, string bn, double p)
        
{
            _uname 
= un;
            _bookname 
= bn;
            _price 
= p;
        }


        
外露属性(定价,书名,用户名)

        
实现基类中的抽象方法以及将任务分派到下面的派生类去
    }


    
/// <summary>
    
/// 作为租赁业务的一个基类,帮助实现ROOT类并增加租赁相关的属性和方法。
    
/// </summary>

    public abstract class Hire : Root
    
{
        
系列的私有字段

        
外露属性(定价,书名,用户名,天数,日租金)

        
实现基类中的抽象方法以及将任务分派到下面的派生类去
    }

}

篇幅限制,我不做太多的解说,我相信真实案例代码的展示+你自己学习后的总结会比我解说得更好。实现的类代码如下:
实现买书的逻辑↓

namespace EBook
{
    
/// <summary>
    
/// 这个类处理会员购买书,我们假设都只是买一本,要买多本的朋友自己想办法,哈哈
    
/// </summary>

    public class Buy : Sell
    
{
        
public Buy(B_Type bt, string un, string bn, double p)
            : 
base(un, bn, p)
        
{
            _btype 
= bt;
            _uname 
= un;
            _bookname 
= bn;
            _price 
= p;
        }

        
        
/// <summary>
        
/// 根据书的类型来定折扣,当然,这里的折扣本来是应该从数据库或者配置文件中取的,我们演示就固化到这里
        
/// </summary>
        
/// <returns></returns>

        public override double TGetMoney()
        
{
            
switch (_btype)
            

                
case B_Type.novel:
                    _cash 
= _price * 0.5;
                    
break;
                
case B_Type.life:
                    _cash 
= _price * 0.8;
                    
break;
                
default :
                    _cash 
= _price;
                    
break;
            }

            
return _cash;
        }

        
/// <summary>
        
/// 执行插入数据库的操作,但是我们这里不需要,只要把结果显示出来
        
/// 所以我们让他给我们返回一句话就OK了。
        
/// </summary>
        
/// <returns></returns>

        public override string TExecute()
        
{
            
return "尊敬的会员:" + _uname + ",您购买《" + _bookname + "》,定价为:" + _price + ",折扣后为:" + GetMoney().ToString();
        }

    }

    
/// <summary>
    
/// 增加有个处理零售客户的类,大致逻辑是一样的,只是说折扣不同
    
/// </summary>

    public class SBuy : Sell
    
{
        
public SBuy(B_Type bt, string un, string bn, double p)
            : 
base(un, bn, p)
        
{
            _btype 
= bt;
            _uname 
= un;
            _bookname 
= bn;
            _price 
= p;
        }

        
        
/// <summary>
        
/// 根据书的类型来定折扣,当然,这里的折扣本来是应该从数据库或者配置文件中取的,我们演示就固化到这里
        
/// </summary>
        
/// <returns></returns>

        public override double TGetMoney()
        
{
            
switch (_btype)
            

                
case B_Type.novel:
                    _cash 
= _price * 0.6;
                    
break;
                
case B_Type.life:
                    _cash 
= _price * 0.9;
                    
break;
                
default :
                    _cash 
= _price;
                    
break;
            }

            
return _cash;
        }

        
/// <summary>
        
/// 执行插入数据库的操作,但是我们这里不需要,只要把结果显示出来
        
/// 所以我们让他给我们返回一句话就OK了。
        
/// </summary>
        
/// <returns></returns>

        public override string TExecute()
        
{
            
return "尊敬的顾客:" + _uname + ",您购买《" + _bookname + "》,定价为:" + _price + ",折扣后为:" + GetMoney().ToString();
        }

    }

}

实现租书的逻辑↓

namespace EBook
{

    
/// <summary>
    
/// 租书
    
/// 分析:租书的时候是不需要支付租金的,但是需要支付押金
    
/// </summary>

    public class Rent : Hire
    
{
        
/// <summary>
        
/// 初始化对象
        
/// </summary>
        
/// <param name="un">用户名</param>
        
/// <param name="bn">书名</param>
        
/// <param name="p">书的定价</param>

        public Rent(string un, string bn, double p)
        
{
            _uname 
= un;
            _bookname 
= bn;
            _price 
= p;
        }


        
public override double TGetMoney()
        
{//直接返回实际支付的现金
            return _cash;
        }

        
/// <summary>
        
/// 将顾客支付的押金写入数据库,这里我们是打印出来
        
/// </summary>
        
/// <returns></returns>

        public override string TExecute()
        
{
            
return "尊敬的顾客,您租借《" + _bookname + "》,本书定价为:" + _price + "元,请支付押金" + _price + "元,实际支付" + TGetMoney().ToString() + "";
        }

    }

    
/// <summary>
    
/// 会员还书
    
/// 分析:还书的时候需要退还押金并支付租金,我们直接把租金在押金里面硬性扣除
    
/// 不同的是这个是会员还书,所以租金和普通顾客的租金有区别
    
/// </summary>

    public class M_Back : Hire
    
{
        
/// <summary>
        
/// 初始化对象
        
/// </summary>
        
/// <param name="un">用户名</param>
        
/// <param name="bn">书名</param>
        
/// <param name="day">租赁天数</param>
        
/// <param name="bt">书的类型</param>

        public M_Back(string un, string bn, int day, B_Type bt)
        
{
            _uname 
= un;
            _bookname 
= bn;
            _day 
= day;
            _btype 
= bt;
        }


        
public override double TGetMoney()
        
{//直接返回应找零现金
            return _deposit - GetRent();
        }

        
/// <summary>
        
/// 计算书的租金
        
/// </summary>
        
/// <returns></returns>

        private double GetRent()
        
{
            
switch (_btype)
            
{
                
case B_Type.novel:
                    _cash 
= Convert.ToDouble(_day) * 0.1;
                    
break;
                
case B_Type.life:
                    _cash 
= Convert.ToDouble(_day) * 0.5;
                    
break;
                
case B_Type.magazine:
                    _cash 
= Convert.ToDouble(_day) * 0.1;
                    
break;
            }

            
return _cash;
        }

        
/// <summary>
        
/// 将顾客支付的押金写入数据库,这里我们是打印出来
        
/// </summary>
        
/// <returns></returns>

        public override string TExecute()
        
{
            
return "尊敬的顾客,您租借《" + _bookname + "》,共计:" + _day + "天,已支付押金" + _deposit + ",实际产生租金" + GetRent() + "元,应找您" + TGetMoney() + "";
        }

    }


    
/// <summary>
    
/// 普通顾客还书
    
/// 分析:还书的时候需要退还押金并支付租金,我们直接把租金在押金里面硬性扣除
    
/// </summary>

    public class S_Back : Hire
    
{
        
/// <summary>
        
/// 初始化对象
        
/// </summary>
        
/// <param name="un">用户名</param>
        
/// <param name="bn">书名</param>
        
/// <param name="day">租赁天数</param>
        
/// <param name="bt">书的类型</param>

        public S_Back(string un, string bn, int day, B_Type bt)
        
{
            _uname 
= un;
            _bookname 
= bn;
            _day 
= day;
            _btype 
= bt;
        }

        
/// <summary>
        
/// 直接应该退给顾客多少钱
        
/// </summary>
        
/// <returns></returns>

        public override double TGetMoney()
        
{//直接返回应该找零的现金,已交的押金减去实际的租金
            return _deposit - GetRent();
        }

        
/// <summary>
        
/// 计算书的租金
        
/// </summary>
        
/// <returns></returns>

        private double GetRent()
        
{
            
switch (_btype)
            
{
                
case B_Type.novel:
                    _cash 
= Convert.ToDouble(_day) * 0.5;
                    
break;
                
case B_Type.life:
                    _cash 
= Convert.ToDouble(_day) * 1d;
                    
break;
                
case B_Type.magazine:
                    _cash 
= Convert.ToDouble(_day) * 0.3;
                    
break;
            }

            
return _cash;
        }

        
/// <summary>
        
/// 将顾客支付的押金写入数据库,这里我们是打印出来
        
/// </summary>
        
/// <returns></returns>

        public override string TExecute()
        
{
            
return "尊敬的顾客,您租借《" + _bookname + "》,共计:" + _day + "天,已支付押金" + _deposit + ",实际产生租金" + GetRent() + "元,应找您" + TGetMoney() + "";
        }

    }

}

定义工厂类,处理按照会员类型返回具体的类

using EBook;
/// <summary>
/// 工厂类主要是按照会员类型将具体使用那个类返回出去
/// </summary>

public class Factory
{
    
private U_Type _utype;    //会员类型
    private B_Type _btype;    //书的类型
    private S_Type _stype;    //交易类型
    private H_Type _htype;    //是租书还是还书
    private string _bookname; //书名
    private string _uname;    //用户名
    private double _price;    //书的定价
    private int _day;         //租借的天数 

    
public Factory(U_Type ut,B_Type bt,S_Type st, string bn,string un,double p)
    
{
        _utype 
= ut;
        _btype 
= bt;
        _stype 
= st;
        _bookname 
= bn;
        _uname 
= un;
        _price 
= p;
    }

    
/// <summary>
    
/// 因为这个并不参与到最初的类实例化中去
    
/// 比如是买书,那根本谈不上是租还是还,所以单独列出来
    
/// </summary>

    public H_Type Htype
    
{
        
get return _htype; }
        
set { _htype = value; }
    }

    
public int Day
    
{
        
get return _day; }
        
set { _day = value; }
    }

    
/// <summary>
    
/// 根据交易类型来判断给那一个方法处理
    
/// </summary>
    
/// <returns></returns>

    public Root HorS()
    
{
        
if(_stype==S_Type.hire)
            
return GetHire();
        
else
            
return GetBuy();
    }

    
/// <summary>
    
/// 根据会员的类型来判断返回那一个被初始化的类
    
/// </summary>
    
/// <returns></returns>

    private Sell GetBuy()
    
{
        
if(_utype==U_Type.member)
            
return new Buy(_btype, _uname, _bookname, _price);
        
else
            
return new SBuy(_btype, _uname, _bookname, _price);
            
    }

    
/// <summary>
    
/// 根据是租书还是还书(又判断顾客类型)来初始化对应的类
    
/// </summary>
    
/// <returns></returns>

    private Hire GetHire()
    
{
        
if (_htype == H_Type.rent)
            
return new Rent(_uname,  _bookname, _price);
        
else
        
{
            
if (_utype == U_Type.member)
                
return new M_Back(_uname, _bookname, _day, _btype);
            
else
                
return new S_Back(_uname, _bookname, _day, _btype);
                
        }

    }

}

到这里为止,我们这个书店的程序逻辑就设计完毕了。
篇幅限制,具体的调用我就不多做解说,欢迎大家一起探讨,学习。

原文地址:https://www.cnblogs.com/beniao/p/1108068.html