设计接口

 1 有一个基类容器包含所有职员。 2 共同性操作,比如获得该发的薪水、结薪作为基类的虚函数。 3 特殊操作,比如某类职员的报到、具体薪水计算情况作为子类的一般函数。 比如: ------------------------------------ class Employee{ public: RMB getSalary() const = 0; }; // 钟点工 class HourWorker: public Employee{ public: checkIn( Time ); // 开工和手工登记 checkOut( Time ); Time getHourCount() const; // 总工作时间 }; // 月工(一般员工) class MonthWorker: public Employee{ public: overWork( Time ); // 加班登记 leave( Time ); // 休假登记 RMB getDefSalary(); // 返回底薪 RMB getRealSalary();// 返回实际应发工资 }; ------------------------------------ 如果只需要知道一般性的信息,可以搜索职员表即可得到该发薪水。 =========================================== 假如要获得详细信息,或者特定操作,那么有两种选择: 1 RTTI 遍历职员表,用 dynamic_cast 转换,如: ------------------------------------ for( 每个Employee ){ if( HourWorker* p = dynamic_cast< HourWorker* > pEmployee ) HourWorkerShow( p ); else if( MonthWorker* p = dynamic_cast< MonthWorker* > pEmployee ) MonthWorkerShow( p ); else ErrorLog( "具体的错误信息" ); } ------------------------------------ 很多人不喜欢 cast, 认为这不是纯正的OOP。 可以看到,这个方法有个缺点,当你添加了新的子类的时候,你必须修改原有代码。所以在所有转换失败的时候,我推荐写ErrorLog,以便避免遗漏。 另外,很容易看到,若是给 Employee 一个虚函数 show,就可以避免上面的RTTI: ------------------------------------ Employee{ public: ... show(); } /// for( 每个Employee ){ Employee.show(); } ------------------------------------ 这种方法更加oop一些; 不过一来这会使得类的设计复杂化( 我们应该实现完备的最小接口 );二来,很多情况下,你不一定有权利修改类体系。 =========================================== 2 为每个子类提供一个容器 这个做法比起前者更加规整一些 —— 而且很多情况下很适用。 假如我们需要添加某个职员的加班信息,我们往往已经知道他是“月工”。 比如: ------------------------------------ // id 号月工职员加班,添加加班记录。 addOverWork( IdType id, Time t ){ // moonWorkerSet 为月工集合 moonWorkerSet. find( id ). overWork( t ); } // id 号钟点工闪人,checkout workerCheckout( IdType id, Time t ){ // hourWorkerSet 为钟点工集合 hourWorkerSet. find( id ).checkOut( t ); } ------------------------------------ =========================================== 无论是用一个总集合RTTI,还是总集合+分集合 都有自己的好处。 若是连接数据库,你可以根据数据库本身的结构决定如何取舍。

 

最后我还是决定采用cast  
   
  期间,我发现使用visitor模式可以避免cast,不过它使设计复杂化了  
   
  visitor   实现:  
   
  EmployeeVisitor  
  {  
  public:  
    virtual   void   getHourWorkerInfo(HourWorker   *   pEmplyee);  
    virtual   void   getMonthWorkerInfo(MonthWorker   *   pEmplyee);  
  }  
   
   
  EmployeeInfoGetter   :public   EmployeeVisitor  
  {  
      void   getHourWorkerInfo(MonthWorker   *   pEmplyee)  
    {  
            //此处调用派生类的特殊函数,取得月薪员工的具体信息        
    }  
    void   getHourWorkerInfo(HourWorker   *   pEmplyee)  
    {  
            //此处调用派生类的特殊函数,取得钟点员工的具体信息        
    }  
  }  
   
   
  class   Employee{  
  public:  
   
  virturl   RMB   getSalary()   const   =   0;  
  vitrual   void   Accept(EmployeeVisitor   *pVisitor);  
  };  
   
  //   钟点工  
  class   HourWorker:   public   Employee{  
  public:  
  checkIn(   Time   );   //   开工和手工登记  
  checkOut(   Time   );  
  Time   getHourCount()   const;   //   总工作时间  
   
  void   Accept(EmployeeVisitor   *pVisitor)  
  {  
      pVisitor->getHourWorkerInfo(this);  
  }  
   
  };  
   
   
  //   月工(一般员工)  
  class   MonthWorker:   public   Employee{  
  public:  
  overWork(   Time   );   //   加班登记  
  leave(   Time   );   //   休假登记  
  RMB   getDefSalary();   //   返回底薪  
  RMB   getRealSalary();//   返回实际应发工资  
   
  void   Accept(EmployeeVisitor   *pVisitor)  
  {  
      pVisitor->getMonthWorkerInfo(this);  
  }  
   
  };  
   
  //使用----------------------------------------  
  for(   每个Employee   *pEmployee)  
  {    
          EmployeeVisitor*   getterVisitor   =   new     EmployeeInfoGetter;      
          pEmployee->Accept(getterVisitor);          
  }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值