煮酒论坛

 找回密码
 申请新用户
搜索
热搜: 活动 交友 discuz
查看: 4469|回复: 7

《设计模式》与《重构》

[复制链接]
发表于 2005-3-18 12:16:20 | 显示全部楼层 |阅读模式
 

          《设计模式》与《重构》


  理解了面向对象?不,如果你把相关代码分散在多个class里,如果对现实世界到机算机程序语言的表述,不以面向对象思想进行映射。既使你有了一个类,它也许会较为丑陋。
  如果不对某个相似的实体或功能进行抽象,那你就没有遵循封装的原则。对象的消息也有可能较为凌乱。
  多态与动态绑定是面向对象技术的核心概念。利用此特性,程序语言呈现出灵巧与优雅的特质,虽然有时候它会让人难以理解。
  需要了解api的细节与服务器及各种工具的配置及使用技巧。可是我们也能象api一样去设计(而不是实现)程序,也能让应用程序象我们使用的工具一样好用。
  不是实现,而是设计。











[此贴子已经被作者于2005-3-22 8:57:27编辑过]

 楼主| 发表于 2005-3-18 12:18:11 | 显示全部楼层
一、《重构》-- 改善既有代码的设计
  1、TTD 、XP与Refactoring
    XP(极限编程)获得了14届软件工程方法学JOLT大奖。它被候捷认为是重型开发与轻型开发之间的区别。XP认为中小型项目不适合按传统的软件工程方法进行--汗牛充栋的文档,需求的错误被持续等。这损害了软件需求的快速变化的适应能力。
    XP中的核心是TTD与Refactoring。很多人都己经知道测试的重要,各种语言也有相应的测试工具使用。XP更强调测试,因为软件处在不断的变化(既所谓Refactoring)中,Refactoring这个词应该是伴随着XP这个概念一起流行的。虽然在《重构》这本书中Refactoring这个概念来自于SmallTallk。
    只是很多经理都不太赞成结对编程。对它所描述的美好图景将信将疑。
    我记得我的前任经理认为,要实现结对编程,真正的提高效率,需要较为优秀的程序员。不然的话,有人会偷懒。呵呵。你看Driver与Navigator哪个不是身怀绝技?
      2、《重构》这本书
    这本书熊节不认为它应该成为经典,经典应该成为一种高山仰止的东西,例如《设计模式》。而它应该成为程序员的空气与水。我们必须时刻重构代码,特别是当有了坏味道(bad smell)的时候。
    必须有测试。你的测试用例将不必修改,因为重构将不改变现有可查功能。必须小步前进,确保不带来臭虫(bug)。
    它是在实践中获得的经验。如果你要掌握它,你必须去实践。熊节说,从最简单的Extract Method开始吧。
    我们比较幸运,因为那么多IDE有了Refactoring这样一个专门的菜单。至少Java的IDE是这样。
  3、这本书重要的概念与章节
    关键词:概念、坏味道、测试体系、步进,小规模、工具
    什么是重构?去看这本书吧,我起先也不知道。在不知道的情况下,我使用了Extract Method。可是,读了这本书才知道pull up xxx、pull down xxx是什么。
    在Martin Fowler写这本书的时候,没有IDE上有Refactoring这项菜单,JB9没有,Eclipse2也没有。
    本书体例上模仿了《设计模式》,你可以按《设计模式》的读者指南去研究这本书。
    我赞成熊节的话,它应该成为程序员的日常的面包与黄油。
  4、实际的例子
    Duplicate Code与Long Method(重复代码与过长方法)
    这是软件内部实现两种最为典型的坏味道。
    重复代码的例子可以参考我所说过的文件上传与取下拉框架的例子。
    以下是对一个过长方法的处理过程:
    旧代码片断
    else if (act.equals("list")) {
            String temppath = this.getServlet().getServletContext()
                    .getRealPath("/")
                    + "roadmanage/reports/xlsfile/xlstemplate/";
            String _path = this.getServlet().getServletContext().getRealPath(
                    "/")
                    + "roadmanage/reports/xlsfile/";
            String _file = "roadManageMonthReport.xls";
            String to_file = "roadManageMonthReport.xls";

            if (!ReportUtil.copy_template_file(temppath + _file, _path
                    + to_file)) {

                log.error("拷贝文件出现错误,,,,,,,,,,,,,,,,,,");

                throw new ReportException();
            }

            //检查月报选择情况
            String report_select[] = request
                    .getParameterValues("select_report");
            int start_line = 1;

            //报表数据参数对象
            GetDataPara r_data_para = new GetDataPara();
            //得到机构
            r_data_para.setOrg_id(user.getOrgID());

            //按月查询
            r_data_para.setYear(year);
            r_data_para.setMonth(month);

            //如果是期间查询
            //${FIXME} 增加期间查询参数
            //
            String period = null;

            if (is_period){//是期间查询

              String start_date = request.getParameter("start_date");
              String end_date = request.getParameter("end_date");
              if (start_date!=null&&end_date!=null){
                period = start_date+" 到 "+end_date;
                try{
                 r_data_para.setStart_date(new java.sql.Date(DateUtil.parse(start_date).getTime()));
                 r_data_para.setEnd_date(new java.sql.Date(DateUtil.parse(end_date).getTime()));

                }catch(Exception ex){
                  log.error("期间查询时,查询参数有误!",ex);
                  throw new ReportException();
                }


              }else{
                log.error("期间查询时,查询参数有误!");
                throw new ReportException();
              }


            //是期间查询 ,并且开始时间小于结束时间
            if (DateUtil.parse(start_date).before(DateUtil.parse(end_date))){
              r_data_para.setIs_period(true);
             }else{
               //互换时间
               r_data_para.setStart_date(new java.sql.Date(DateUtil.parse(start_date).getTime()));
               r_data_para.setEnd_date(new java.sql.Date(DateUtil.parse(end_date).getTime()));
               r_data_para.setIs_period(true);
             }
            }



            if (report_select != null && report_select.length > 0) {
                log.info("所选择的月报个数:" + report_select.length);
                int size = report_select.length;
                String period_str = this.getCountPeriod(r_data_para);

                for (int i = 0; i < size; i++) { //逐个检查选择值
                    log.info("月报名:" + report_select);
                    if (report_select.equals("month_report1")) {
                        //得到路政申请事项统计表数据 己加上公路占用数据 wangsy 2004-11-11
                        HashMap roadPermitMap = RoadPermitReportDataMap
                                .getRoadPermitData(r_data_para);

                       //加上期间字符串 2005-01-31 wangsy
                       roadPermitMap.put("F2",period_str);


                        ReportUtil.toXlsFile(_path, to_file, start_line, 0,
                                roadPermitMap);
                    } else if (report_select.equals("month_report2")) {
                        //得到路政案件综合报表
                        HashMap dataMap = RoadCaseReportDataMap
                                .getRoadPermitData(r_data_para);

                      //加上期间字符串 2005-01-31 wangsy
                       dataMap.put("F2",period_str);


                        ReportUtil.toXlsFile(_path, to_file, start_line, 1,
                                dataMap);

                    } else if (report_select.equals("month_report3")) {

                        //得到施工安全管理统计表数据
                        HashMap constructionSafeMap = ConstructionSafeManageDataMap
                                .getConstructionSafeData(r_data_para);

                        //加上期间字符串 2005-01-31 wangsy
                       constructionSafeMap.put("E4",period_str);

                        ReportUtil.toXlsFile(_path, to_file, start_line, 2,
                                constructionSafeMap);
                    } else if (report_select.equals("month_report4")) {
                        //得到交通事故案件综合报表
                        HashMap dataMap = CaseSumReportDataMap.getRoadCaseData(r_data_para);

                        //加上期间字符串 2005-01-31 wangsy
                       dataMap.put("F2",period_str);

                        ReportUtil.toXlsFile(_path, to_file, start_line, 3,
                                dataMap);

                    } else if (report_select.equals("month_report5")) {
                        //得到交通事故案件登记表数据
                        HashMap accidentCaseRegisterMap = AccidentCaseRegisterDataMap
                                .getAccidentCaseData(r_data_para);

                       //加上期间字符串 2005-01-31 wangsy
                       accidentCaseRegisterMap.put("F2",period_str);

                        ReportUtil.toXlsFile(_path, to_file, start_line, 4,
                                accidentCaseRegisterMap);
                    } else if (report_select.equals("month_report6")) {
                        //得到资源文件
                        String file = this.getServlet().getServletContext()
                                .getRealPath(Constants.PROPERTIES_FILE_PATH);
                        r_data_para.setProperties_file(file);

                        //交通事故案件分析表
                        HashMap dataMap = CaseAnalyseReportDataMap
                                .getRoadCaseData(r_data_para);

                      //加上期间字符串 2005-01-31 wangsy
                       dataMap.put("D2",period_str);

                        ReportUtil.toXlsFile(_path, to_file, start_line, 5,
                                dataMap);

                    } else if (report_select.equals("month_report7")) {
                        //得到事故案件待处登记表数据
                        HashMap accidentCaseWaitingRegisterMap = AccidentCaseWaitingRegisterDataMap
                                .getAccidentCaseWaitingData(r_data_para);

                       //加上期间字符串 2005-01-31 wangsy
                       accidentCaseWaitingRegisterMap.put("F2",period_str);

                        ReportUtil.toXlsFile(_path, to_file, start_line, 6,
                                accidentCaseWaitingRegisterMap);
                    } else if (report_select.equals("month_report8")) {
                        //指路产修复表,暂未加上
                        ;
                    }
                }
            }

            String _reportname = org_name+year+"年"+month+"月管理报表.xls";
            if (r_data_para.isPeriod_Query()){
              _reportname = org_name+"期间("+period+")管理报表.xls";
            }

            ReportUtil.getReturnPage(_path + to_file, response, _reportname);
            return null;

        }

它太长了,很累吧。看看缩减后的情况
新代码片断

  else if(act.equals("list")){

      //拷贝excel模板文件
      copyExcelFile(new_temppath, new_path, _file, to_file);

      //得到参数对象
      GetDataPara r_data_para = getDataPara(
          request, year, month, isPeriod(request), UserMap.getUserFromRequest(request));

      //月报选择情况
      String report_select[] = request.getParameterValues("select_report");

      //处理报表
      genReport(new_path, to_file, report_select, r_data_para);

      //Report Name
      String _reportname = org_name + year + "年" + month + "月管理报表.xls";
      if(r_data_para.isPeriod_Query()){
        _reportname = org_name + "期间(" + getCountPeriod(r_data_para) +
                      ")管理报表.xls";
      }
      //return client
      ReportUtil.getReturnPage(new_path + to_file, response, _reportname);

      return null;

    }


[此贴子已经被作者于2005-3-18 12:19:16编辑过]

 楼主| 发表于 2005-3-18 12:20:14 | 显示全部楼层
二、《设计模式》-- 适应变化、可重用
  敬畏。保持这种心态,对自己将会有更接近的一种认知。
  这是一本无法简单描述的书。
  它是一般问题的通用设计实现。这种设计较为优雅,但可能你将觉的较为繁复。但是它使你的代码reuse,不是refuse,:)
  它不包括面向特定应用设计模式,如web或界面程序的MVC模式,分布式系统设计模式,DAO模式。
  它比《重构》更需要实践。我在项目中实现了一个Composite模式,虽然读者指南认为它是一个较为简单的模式。
  我一点也不这么认为。
  1、模式与面向对象
    面向对象技术是《设计模式》》的基础。阅读这本书之前,你必须深刻理解接口编程。对多态与动态绑定了然于心。
    不然,你几乎无法阅读它。
  2、可重用其本质是适应变化
    可重用其本质是适应变化。
    分模块、分层、从两层到三层架构设计都是在解耦。将变化的东西与不变的东西分开,这句话说的多好。
    无论是面向对象还是面向过程。对现实世界的抽象能力是任何工具都不能提供的。从用例图到状态图。从八皇后、背包及车站问题到回溯、递归与贪婪算法。
 3、模式之间有着设计的关联

    我只能说,对此并没有足够的体会。它对设计策略进行着选择,如Compsite模式就允许你有一个父结点(树)的引用。



  模式是一种抽象词汇,代表着深遂的含义。这本书称为复用面向对象软件的基础,对,是基础。对模式,对现实世界的抽象表达能力。那么多的天才推动着软件技术的迅猛发展,面对如此巨大与深刻的影响。

  我不得不保持着敬畏。

  Erich Gamma,Richard Helm,Ralph Johnson,John Vissides ,让我们记住这此名字。

  同时,对译者表达一下我们的敬意。

  他们是:吕建,李英军,马晓星,蔡敏,刘建中



[此贴子已经被作者于2005-3-18 12:22:35编辑过]

发表于 2005-3-21 17:26:58 | 显示全部楼层
你读的很有心得!有机会我们可以交流一下!


[此贴子已经被作者于2005-3-21 17:27:40编辑过]

 楼主| 发表于 2005-3-22 09:01:07 | 显示全部楼层
好啊,呵呵。

现在我主要是用java,做一些高速公路交通路政业务方面的web应用。

你呢,用什么语言?
发表于 2005-3-23 10:22:44 | 显示全部楼层
我么,用c++较多,也兼搞些.net(c#),不过我想从模式设计上应该有很多相同的地方!
 楼主| 发表于 2005-3-24 14:07:36 | 显示全部楼层
现在,我正在对文件上传进行第二次封装。

现在有一个FileUploadAction类,它承担一部分MVC中的控制器功能,它能得到request,response等对象。

这个类里有一个FileUpload对象。同时有一个FileUploadConfig对象。


使用者组装一个FileUploadConfig对象,给我的FileUploadAction对象。由这个Action来处理相关的操作。这个Action封装显示页面。

这意味着,其它各点不再需要知道FileUpload对象的存在。客户端只需知道有这样一个更加完整的Action,你只需要通过FileUploadConfig对象对上传操作进行配置一下。

它就能很好的工作。

这意味着,客户端(需要文件上传服务的点)只需要在点上加一个链接,调用我的文件上传服务,然后拿到上传信息进行列表既可。
调用代码不必知道FileUpload对象的存在。

这样封装效果更好。


[此贴子已经被作者于2005-3-24 14:08:41编辑过]

 楼主| 发表于 2005-3-24 14:11:51 | 显示全部楼层
另外关于Composite。我觉的关键是这样设计利用了业务方法的动态绑定以及组装过程的手工控制。

它可以避免你写烦人的递归方法。

它有两个关键概念:单一部件与组合部件。


[此贴子已经被作者于2005-3-24 14:12:34编辑过]

您需要登录后才可以回帖 登录 | 申请新用户

本版积分规则

小黑屋|手机版|Archiver|守望轩 ( 湘ICP备17013730号-2 )|网站地图

GMT+8, 2018-9-22 13:38 , Processed in 0.028383 second(s), 17 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表