<?xml version="1.0" encoding="utf-8" ?>
<!-- generator="FEEDCREATOR_VERSION" -->
<rss version="2.0" xmlns:sns="http://blog.sina.com.cn/sns">
    <channel>
        <title>SuperMan</title>
        <description></description>
        <link>http://blog.sina.com.cn/ycpeng</link>
        <lastBuildDate>Fri, 17 Jul 2009 18:35:50 GMT+8</lastBuildDate>
        <generator>FEEDCREATOR_VERSION</generator>
        <language>zh-cn</language>
        <copyright>Copyright 1996 - 2009 SINA Inc. All Rights Reserved.</copyright>
        <pubDate>Fri, 17 Jul 2009 10:35:50 GMT+8</pubDate>
        <item>
            <title>用HSCALE实现MySQL的数据分布式存储</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701009xc6.html</link>
            <description><![CDATA[<p>
针对单个表过大造成的性能问题，MySQL在5.1开始引入了分区表(<strong>partition</STRONG>)，可以将数据在内部拆分存储，对应用透明，但是分区表只能将表在同一个数据库内部分解，而且对于表的维护(比如执行alter
table)还是比较麻烦。手工分表也是一个解决方法，手工分表还有一个好处是可以将表分布到不同的服务器中，实现分布式存储。但是手工分表要求应用程序做相应的改写，以支持从不同的表中来存取数据。</P>
<p><a HREF="http://www.hscale.org/display/HSCALE/Home"><strong>HSCALE</STRONG></A>简单来说就是一个支持手工分表的中间层，对于应用来说看起来还是一个表，而由HSCALE来负责底层子表的数据存取。HSCALE是基于<a HREF="http://forge.mysql.com/wiki/MySQL_Proxy"><strong>MySQL
Proxy</STRONG></A>的一个插件应用，通过MySQL Proxy的<strong><a HREF="http://www.lua.org/">lua</A></STRONG>脚本拦截分拆对应的SQL语句来实现数据的分布存储，而且使用lua脚本可以自由定制分表策略，比起MySQL自己的partition更加灵活些。现在版本还是0.2，功能有限，只能实现同库分表，但是基于MySQL
Proxy的架构，未来要实现示分库分表也不是什么难事。</P>
<p>作者利用<a HREF="http://www.ningoo.net/html/2008/mysql_load_test_tool_mysqlslap.html"><strong>mysqlslap</STRONG></A>对HSCALE和MySQL
Proxy做了几组性能测试，结果参考<a HREF="http://pero.blogs.aprilmayjune.org/2008/05/05/benchmark-mysql-proxy-and-hscale/">这里</A>，还有<a HREF="http://pero.blogs.aprilmayjune.org/2008/05/05/update-benchmark-hscale-with-mysql-proxy-070-svn-against-061/">这里</A>。</P>
<p>当然，现在MySQL
Proxy和HSCALE都是刚刚起步，要在产品库中应用还有很长的一段路要走，从上面的性能测试中可以看到基于最新的MySQL Proxy
0.7版的HSCALE性能有了较大的提升，期待后续版本有更好的表现。</P>]]></description>
            <author>klvein</author>
            <category>KM(数据库)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701009xc6.html#comment</comments>
            <pubDate>Thu, 17 Jul 2008 02:13:07 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701009xc6.html</guid>
        </item>
        <item>
            <title>MySQL数据表类型</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701009xbx.html</link>
            <description><![CDATA[<p>MySQL数据表支持六种类型
，分别是：BDB、HEAP、ISAM、MERGE、MYISAM、InnoBDB，这六种又分为两类，单独一类是BDB，称为"事务安全型"(transaction-safe)，其余都属于第二类，称为“非事务安全型"(non-transaction-safe)。下面详细介绍这些表:</P>
<p>事务安全型<br />
BDB 全称是"Brekeley DB",它是Mysql具有事务能力的表的类型，由Sleepycat Software
（<a HREF="http://www.sleepycat.com">http://www.sleepycat.com</A>）开发。它提供了事务控制能力功能，它确保一组命令全部执行成功，或者当任何一个命令出现错误时所有命令的结果都被回退，可以想像在电子银行中事务控制能力是非常重要的。</P>
<p>非事务安全型<br />
HEAP<br />
HEAP表是MySQL表中访问最快的表，主要是由于这类表使用保存期在内存中的散列索引，但必须注意的是，如果MySQL或者服务器崩溃，表中数据全部丢失。<br />

ISAM<br />
ISAM表是MyISAM类型出现之前，MySQL表使用的默认类型，建议改用MyISAM。<br />
MEREG<br />
MEREG是一种值得关注的新式表，它是由一组MyISAM表组成，之所合并主要出于性能上考虑，因为它能够提高搜索速度，提高修复效率，节省磁盘空间。<br />

MyISAM<br />
MyISAM是MySQL表默认的类型，它是基于ISAM类型，但它增加了许多有用的扩展，下面是MyISAM一些优点：<br />
1.比ISAM表更小，所占资源更少<br />
2.可以在不同平台间二进制移植<br />
表的类型在创建表时指定。在下面这个例子中我们创建了一个HEAP类型的表：<br />
CODE</P>
<p>InnoBDB<br />
这是最近加入的新表，具有以下特性：<br />
事务处理机制<br />
崩溃后能立即恢复<br />
支持外键功能，级联删除<br />
支持并发能力<br />
在硬盘上的存储方式：InnoBDB frm</P>
<p>数据表的可移植性<br />
通用方法：把数据表的内容导出到一个文本文件中，然后拷贝到硬盘上，导入数据库里面。就文件层次的操作来说，某些数据表是可以单独拷贝的看表<br />

ISAM No<br />
MyIASM Yes<br />
BDB No<br />
InnoBDB Yes</P>
<p><br />
mysql &gt;CREATE TABLE email_addresses TYPE=HEAP
(<br />
- &gt;email char(55) NOT NULL,<br />
- &gt;name char(30) NOT NULL,<br />
- &gt;PRIMARY KEY(email) );</P>]]></description>
            <author>klvein</author>
            <category>KM(数据库)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701009xbx.html#comment</comments>
            <pubDate>Thu, 17 Jul 2008 01:55:16 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701009xbx.html</guid>
        </item>
        <item>
            <title>浅析软件项目管理中十个误区
</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000anz.html</link>
            <description><![CDATA[<DIV>&nbsp;文章来源:<FONT FACE="宋体">http://manager.csdn.net/n/20051213/30907.html</FONT></DIV>
<DIV><FONT FACE="宋体">随着计算机硬件水平的不断提高，计算机软件的规模和复杂度也随之增加。计算机软件开发从“个人英雄”时代向团队时代迈进，计算机软件项目的管理也从“作坊式”管理向“软件工厂式”管理迈进。这就要求软件开发人员特别是软件项目管理人员更深一步地理解和掌握现代软件工程的理论方法，完成思想观念上的转变。笔者在此分析了10个在现代项目管理中思想观念上容易陷入的误区，希望能够抛砖引玉，引发大家更多的思索和讨论。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
误区1：在项目的需求分析阶段，开发方与客户方在各种的问题的基本轮廓上达成一致即可，具体细节可以在以后填充。因为无论开始时有多么细致，
以后对需求的修改几乎是必然的。分析：这是一种非常危险的思想。实际上许多软件项目失败的最主要的原因就是需求阶段对问题的描述不够细致，导致后来预算超出或者时间
进度达不到要求。正确的做法是：在项目需求分析阶段，双方必须全面地尽可能细致地讨论项目的应用背景、功能要求、性能要求、操作界面
要求、与其他软件的接口要求，以及对项目进行评估的各种评价标准。并且，在需求分析结束以后，双方还要建立可以直接联系的渠道，以尽
早地对需求变动问题进行沟通。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
误区2：软件项目的需求可以持续不断的改变，而且这些改变可很容易地被实现。分析：的确，在具体实际中由于种种原因客户方很难在需求分析阶段全面而准确地描述所有问题。随着开发进度的推进，往往会有一些需求的
改变。而现代软件工程理论也利用软件的灵活性特点通过各种方式来适应这种情况。不过，这并不表明“软件项目的需求可以持续不断的改变
，而且这些改变可很容易地被实现”。实践表明：随着开发进度的推进，实现软件需求更改所需要的代价呈指数形式增长。假定在需求分析阶
段实现需求更改需要花费1倍的代价；那么，在系统设计和编码阶段，需要花费1.5-6倍的代价；在系统测试阶段需要花费10-20倍的代价；在软
件版本发布以后，甚至可能要花费60-100倍的代价。由此可见，在项目开展过程中，软件需求的改变应当尽量早地提出。这样才可能花费少，
容易被实现。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
误区3：软件程序主要由代码组成，因此编码阶段是整个软件项目的最重要的阶段，应该给与大量的时间，并且集中主要的资源。分析：与以前相比，由于软件的规模和复杂度的增加，以及半自动化软件代码开发平台的出现，现代软件项目管理的中心发生了转移——不是
着重编码阶段，而是着重系统总体/详细设计阶段。一般说来，在现代软件项目管理中各种资源的合理分配比例是：项目论证、风险评估阶段3%
，项目需求分析阶段8%，系统总体/详细设计阶段45%，编码阶段10%，系统测试阶段34%。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
误区4：为了便于代码的维护修改，在系统的详细设计阶段文档工作应该做到写出所有程序的伪码。分析：通常伪码的最大作用是对程序的算法流程进行描述，便于人们深入了解程序的功能和实现过程。可见，在一定程度上伪码的确有利于对
程序代码的维护和修改。但是，我们知道为了保证项目文档和程序代码的一一对应关系，维护程序代码的时候同时需要对项目文档进行维护。伪码和程序代码是非常接近的，对伪码进行维护的话，相当于进行了2倍的程序代码维护。工作量是很大的。所以切合实际的方式应该是对一般
的程序文档做到程序流程图即可，对于涉及了较复杂算法的才需要伪码。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
误区5：既然在项目人员配置中设置了专门的测试人员，那么软件所有的内部测试工作全部应该由测试人员完成。分析：软件程序测试可以分为“白盒法”和“黑盒法”两种方式。由于使用“白盒法”对测试人员各方面素质的种种要求，在进行程序测试时
测试人员总是最优先使用“黑盒法”。他们的工作方式往往是先对程序进行“黑盒法”测试；如果测试没有通过，不得已这才考虑对程序代码
进行“白盒法”测试。显然，这种对“白盒法”有意无意的“逃避”，对软件的可靠性和稳定性构成了威胁。如何解决这个问题？一方面需要
提高对测试人员的要求，另一方面也需要程序员完成部分的“白盒法”测试（实际上，程序员往往也是进行“白盒法”测试的最佳人选）。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
误区6：软件项目管理只是相关技术部门的事情，与公司其他部门无关。分析：在竞争日益激烈的今天，软件项目规模大、复杂度高而且时间要求紧迫。要想提高公司的软件项目管理水平，这就需要提高公司的整体
参与意识，需要公司各个部门协同作战。例如需要会计部门协助进行项目预算，财务管理和费用控制；需要研究部门（技术委员会）指派专家
协助进行各种风险评估，提供技术指导；需要后勤部门提供各种保障。</FONT></P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">误区7：在开发进度滞后的情况下，可以聘请更多的程序员加入到开发团队中，通过增加人力资源来赶上进度。分析：在注重团队开发的时代，开发方应该根据目前的软件项目管理水平慎重考虑这个做法。如果新加入的程序员对目前软件项目的应用行业
有一定了解，并且可以很快适应了开发方的项目管理方式、软件开发风格、团队协作氛围；那么“新人”的加入是有益的。否则，可能会“好
心好意做坏事”。因为尽管其个人能力很高，但是为了使其与大家一起协同工作，开发团队不得不分出人手对其进行与项目有关的技术/业务培
训，更重要的（也是难度最大的）是还要引导其融入团队。这可能需要花费开发团队许多时间和精力，很有可能使项目进度更慢。</FONT></P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
误区8：技术骨干应该成为项目的项目经理，项目经理一定是所有项目成员中薪水最高的。分析：在“软件作坊”时代，这是一种普遍使用而且效果不错的方法；而在“软件工厂”时代，这种方法却带来各种问题，有时甚至直接导致
项目失败。究其原因这主要是因为随着现代软件开发分工的细化，对项目经理的要求也发生了根本的改变——最注重的不是其对某项专业技术
的掌握程度，而是其组织、领导、协调开发团队的能力（当然，可以两者均突出最好）。至于项目经理的薪水问题，这和定薪制度有很大关系
。通常，项目经理执行的是管理人员的薪酬体系，而其他人员执行的是技术人员的薪酬体系。项目经理的薪水在项目成员中是比较高的，但不
一定是最高的。有时候，为了激励技术人员，项目中的技术骨干得到的酬劳比项目经理要高。</FONT>&nbsp;</P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
误区9：只有项目经理以及部门主管才会关心项目整体进度，程序员只关心自己的开发进度。分析：这是一种“官僚”的想法。实际上程序员作为团队中的一员，他不仅仅是在打一份工，更重要的是在参与一件“作品”的创作。在体味
工作的辛苦的同时，程序员更重要的是要享受创作的快感。项目经理不应该漠视程序员对“成就感”的追求，应该向每一个人详细描述最终“
作品”将会如何美妙和令人兴奋，并且在到达最终目标的路上设立一系列的里程碑。每当项目整体推进到一个里程碑的时候，项目经理应该把
这个消息告诉每一位项目成员。实际上，这不仅仅可以让所有的项目成员享受到阶段胜利的喜悦，还可以激发大家更大的工作热情，提高工作
效率。</FONT></P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
误区10：为了保证项目继续，为了留住核心程序员，加薪吧。分析：加薪可以说是很多企业在挽留程序员时所使用的常用方法。这一招可能暂时奏效，不过往往是人留下来了，但副作用也来了——加薪的
人未必见得多干活，没有加薪的人却开始消极怠工了。其实，项目的进行过多地依赖程序员的个人技术是“作坊”时代沿袭下来的“陋习”。
既然IT行业人员的流动是无法控制的，现在项目的执行应该更加注重团体的力量，应该更多的考虑公司整体技术水平和核心技术能力。例如形
成公司自己的专家知识库，类/函数库，第三方控件库，拥有自主版权的开发平台等。另外，实际上程序员萌生去意的原因很大程度上不是薪水
，而是缺少激励和尊重。这需要项目经理使用“老土”一点的办法，找适当的时机对程序员做一做思想工作，向其描述项目的美好未来，让其
感受关心和尊重。总之，要从多方面着手保证项目的顺利开展，而不是简单地加薪。</FONT></P>
</DIV>
]]></description>
            <author>klvein</author>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000anz.html#comment</comments>
            <pubDate>Tue, 04 Sep 2007 02:25:55 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000anz.html</guid>
        </item>
        <item>
            <title>怎样做一个优秀的系统分析师？</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000am7.html</link>
            <description><![CDATA[<DIV>文章来源：<FONT FACE="宋体">http://sd.csdn.net/page/17318865-4f78-441b-861d-e33e16fe8954</FONT></DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
什么是系统分析师?什么样的人是优秀的系统分析师?什么样的人是企业真正需要的系统分析师?系统分析师也许很神秘,也许很抽象,他有很多其他称谓,比如需求分析师、分析师等等。你可以说系统分析师是IT技术专家,也可以说他是业务专家,甚至可以说系统分析师是管理专家,那么他到底是什么?</FONT></DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
也许,有一点我们可以确定,系统分析师连接着用户的需求,系统分析师主导着开发的实现,系统分析师的素质高低对IT项目的成败起到很重要的作用。</FONT></DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
近年来,我国IT软件产业发展规律迅猛,需要大量IT人才,尤其需要居于IT人才金字塔顶端的系统分析师人材,笔者以自己的做系统分析师一些经验和对这个职业的理解，试图用一些文字研究系统分析师的素质和能力模型，以飨读者和广大IT技术人员、系统分析师同仁。</FONT></DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
要想成为一名优秀的系统分析师，首先必须弄明白与系统分析师相关的一些职业理念和相关的工作概念定义。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">一、如何理解系统、信息系统、系统分析、系统设计、系统分析师？</FONT></DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
系统是一组为实现某些结果相互联系、相互作用的部件的集合体。而信息系统是一组完成收集、处理、储存信息和以输出完成商业任务所需信息作为提交的系统。系统分析是理解并详细说明信息系统应该做什么的过程。系统设计是详细说明信息系统的诸多组件在物理上是怎样实施的过程。</FONT></DIV>
<DIV><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
系统分析师是使用信息技术的商业专业人员，利用分析和设计技术解决业务问题。他是团队中的一种角色,主要负责与涉众客户代表协同工作,以便对项目需求进行获取、分析、编写说明规格、确认和管理,也可称需求分析师,业务分析员等。</FONT></DIV>
<DIV>&nbsp;&nbsp;&nbsp;
<FONT FACE="宋体">做一名系统分析师，要首先认识什么是系统分析师。对于同样一件事物的认识，每个人都会不一样，“一千个人有一千个哈姆雷特”，这关乎到认识论。其实,一个人的认识正好折射出了他的经验、水平、层次、能力。一句话，大道由简，我们也许熟悉了很多系统分析方面的技术，然后我们需要问自己是不是真的懂这个职业的本质含义所在，一定不要舍本求末。</FONT></DIV>
<DIV>&nbsp;&nbsp;&nbsp;
<FONT FACE="宋体">上面的定义很简单，但反映了一些基本的要素。系统分析师首先是商业人员，然后才是IT技术人员，但系统分析师不是程序员，他的使命是解决业务问题，手段是信息技术。他不但要理解还要会详细地说明，这意味着他的商业知识、理解分析能力以及表达能力是比较基础的核心能力。还有,
系统分析最重要的是实践过程。系统分析师最好和业务人员打成一片,这样才会获得用户的信任。</FONT></DIV>
<DIV>&nbsp;&nbsp; <FONT FACE="宋体">顺便需要说明的是，信息系统有很多种类型,常见的有OLTP、
MIS、EIS、DSS。当然,你还可以谈很多,其实，任何一个名词都足够写一本书,你就大胆地讲出你的理解吧。但一定要记得总结,用一句话能总结出来就不用两句话,系统分析这个职位对思维的清晰要求颇高。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">二、系统分析师需要哪些技能？</FONT></DIV>
<DIV>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
首先，系统分析师应熟悉如何建立信息系统，这要求相当高的信息技术能力，包括软件工程、主流技术架构、网络、数据库技术等等。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
第二,系统分析师应必须熟悉自己正为之工作的商业行业，以及该行业如何使用各种类型系统的情况。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
最后，系统分析师应需要熟悉相当多的人及其工作方式，因为这些人是信息系统的使用者，或者说是系统分析师的“客户”。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
系统分析师是“通才”，正是因为他们连接了IT和业务。优秀的分析师其实懂三种“世界”的语言，即计算机语言、商业语言、人的语言。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
对于商业，有些分析师一生专门研究一个特定的商业行业，比如制造业、零售业、服务业或贸易行业。一个非常熟悉某特定行业的分析师能够为这个行业的公司解决一些复杂的问题。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
熟悉这个公司则需要花费一些时间，尤其是细节方面，包括组织结构、使命、成功的因素、战略和计划、企业文化和企业价值。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
总之,系统分析师=行业业务专家+IT技术专家+管理专家。</FONT></P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">三、系统分析师解决问题的大致过程是什么？</FONT></P>
<P><FONT FACE="宋体">系统分析师解决问题的大致过程一般如下：</FONT></P>
<P><FONT FACE="宋体">（1）研究和理解问题。</FONT></P>
<P><FONT FACE="宋体">（2）核实解决问题的效益大于成本。</FONT></P>
<P><FONT FACE="宋体">（3）确定解决问题的需求。</FONT></P>
<P><FONT FACE="宋体">（4）制定一套可能的解决方案，提供多种可供选择的方法。</FONT></P>
<P><FONT FACE="宋体">（5）决定最佳方案并推荐给决策层。</FONT></P>
<P><FONT FACE="宋体">（6）详细说明所选方案的细节。</FONT></P>
<P><FONT FACE="宋体">（7）实施解决方案。</FONT></P>
<P><FONT FACE="宋体">（8）监控结果是否达到预期结果。</FONT></P>
<P><FONT FACE="宋体">这个是经过归纳的大致过程,实际还有其他经典的过程,与之的区别只是形式上不同，但求解问题的过程是一致的。</FONT></P>
<P><FONT FACE="宋体">上面的步骤是经过归纳过的，也许不同类型的系统，不同类型的企业工作方法不尽相同，但从宏观的角度看的确是类似的。</FONT></P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">四、系统分析原型法的意义</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
原型(Prototype)
即样品、模型的意思。把系统主要功能和接口通过快速开发制作为“软件样品
”，以可视化的形式展现给用户，及时征求用户意见，从而明确无误地确定用户需求。另外，原型也可用于征求内部意见，作为分析和设计的接口之一，可方便于沟通。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
对原型的基本要求包括：体现主要的功能、提供基本的界面风格、展示比较模糊的部分以便于确认或进一步明确。原型最好是可运行的，至少在各主要功能模块之间能够建立相互连接。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
原型法意义在于可视化、强化沟通、降低风险、节省后期变更成本、提高项目成功率。一般来说，采用原型法后可以改进需求质量。虽然投入了较多先期的时间，但可以显著减少后期变更的时间。原型法投入的人力成本代价并不大，但可以节省后期成本。对于较大型的软件项目来说，原型系统可以成为开发团队的蓝图。另外，原型通过充分和客户交流，还可以提高客户满意度。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
原型法是在计算机技术发展到一定阶段，用户应用需求高涨的情况下发展的一种方法论，但它同时又是对开发人员有高要求的一种方法论。</FONT></P>
<P><FONT FACE="宋体">原型法的基本思想如下:
原型法是确定需求策略，是对用户需求进行抽取、描述和求精。它快速地、选代地建立最终系统工作模型，对问题定义采用启发的方式，由用户作出响应。原型法实际上是一种动态定义技术。</FONT></P>
<P><FONT FACE="宋体">　　原型法被认为对于大多数企业的业务处理来说，需求定义几乎总能通过建立目标系统的工作模型来很好地完成，而且这种方法和严格定义方法比较起来，成功可能性更大。</FONT></P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">原型法开发策略基于如下的假设：</FONT></P>
<P><FONT FACE="宋体">　（1）并非所有的需求在系统开发以前都能准确地说明。</FONT></P>
<P><FONT FACE="宋体">　（2）有快速的系统建造工具。</FONT></P>
<P><FONT FACE="宋体">　（3）项目参加者之间通常都存在通信上的障碍。</FONT></P>
<P><FONT FACE="宋体">　（4）需要实际的、可供用户参与的系统模型(system
model)。</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
文字和静态图形是一种比较好的通信工具，然而其最大的缺点是缺乏直观的、感性的特征，因而往往不易理解对象的全部含义。交互式原型系统能够提供生动活泼的规格说明，用户见到的是一个“活”的、运行着的系统。理解纸面上的系统和操作运行在机器上的系统，其差别是十分显著的。因此，当能够提供一个生动的规格说明成为可能的话，人们就不会满足于一个静止的、被动的规格说明。</FONT></P>
<P><FONT FACE="宋体">　　总之，当提供一个活生生的系统模型时，人们对它的了解将比说明性材料好得多。
　<br/>
　（5）需求一旦确定，就可以遵从严格的方法。</FONT></P>
<P><FONT FACE="宋体">　（6）大量的反复是不可避免的、必要的，应该加以鼓励。</FONT></P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">在信息系统设计的过程中，常用的各种不同形式的部分原型有：<br/>

　（1） 对话原型</FONT></P>
<P><FONT FACE="宋体">　　原型模拟预期的终端交互，使用户可以从屏幕上查看他们将接收什么、进行的操作，并提出遗漏之处，从而加深正确的理解。终端对话的设计效果直接影响着系统的可用性和用户对系统的接受程度。</FONT></P>
<P><FONT FACE="宋体">　（2） 数据输入原型</FONT></P>
<P><FONT FACE="宋体">建立数据输入的原型，可以检查数据的输入速度和正确性，还能进行有效性和完整性的检查。</FONT></P>
<P><FONT FACE="宋体">　（3） 报表系统原型</FONT></P>
<P><FONT FACE="宋体">提供给用户的各种报告应在整个系统实现之前给用户看，报表子系统需要经常进行大量修改以满足系统的需要，因此，可以把报表生成器作为原型。</FONT></P>
<P><FONT FACE="宋体">　（4） 数据系统原型</FONT></P>
<P><FONT FACE="宋体">　　首先生成一个含有少量记录的原型数据库，这样用户和分析师与它可以进行交互，生成报表和显示有用信息。这种交互经常导致产生对不同的数据类型、新的数据域或不同的数据组织方式的需求，还可以在原型化工具的帮助下探索用户将如何使用信息以及数据库是什么样的。</FONT></P>
<P><FONT FACE="宋体">　（5） 计算和逻辑原型</FONT></P>
<P><FONT FACE="宋体">　　有时一个应用逻辑或计算是复杂的。审计员、工程师、投资分析师和其他用户可以使用高级程序设计语言建立他们所需的计算实例。这些实例可以组合在一起构成一个大的系统，与其它应用系统、数据库或终端相连接，用户可以使用这些计算原型检验他们所求结果的准确性。</FONT></P>
<P><FONT FACE="宋体">　（6） 应用程序包原型</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
在一个应用程序包和其它应用系统相连或实际使用之前，可以通过一个小组用户来鉴定这个应用程序包是否令他们满意，若不满意可以进行大量的修改，直到令他们满意。</FONT></P>
<P><FONT FACE="宋体">　（7） 概念原型</FONT> <FONT FACE="宋体"><br/>
&nbsp;&nbsp;&nbsp;
原型法是近年来流行的软件需求捕获方法之一。我们应该明白原型法是手段而不是目的。需要回答的要点是,原型法的背景、概念、定义、意义、如何实现原型、最好能够举例说明。</FONT></P>
<P>&nbsp;&nbsp;&nbsp;
能够回答这些问题才能说明你完全掌握了原型法。很显然,提出这种问题的企业对这种方法在实际工作中是会相当倚重的，因此您不仅要知之还要行之。</P>
<P>&nbsp;&nbsp;&nbsp;
以一个简单的案例来说明，王五是某家大型电子商务贸易公司的系统分析师,他负责做了一个询盘系统。由于询盘系统牵涉到许多抽象专业知识,因此为了便于沟通,王五经过一番研究制作了界面原型设计,并给出了解决方案,领导和客户看了原型设计后通过该需求方案。这个案例说明,今天的需求分析,不再是分析师和客户之间的访谈,更是一种通过实际原型(模型)互相启发,从而发现需求,归纳总结需求的一个实践过程。但我们可以看到,原型法只是一种手段,与用户良好的互动和沟通是获得需求的基本点所在.</P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">六、如何进行有效的需求开发过程?</FONT>
<FONT FACE="宋体"><br/>
&nbsp;&nbsp;&nbsp;
需求描述了客户需要或目标,或者描述了为满足这种需要或目标，产品必须具有的条件或能力,它是种特性,要求产品为涉众提供价值。</FONT></P>
<P>&nbsp;&nbsp;&nbsp;
系统需求是系统必须完成的功能和局限性。功能需求是描述系统必须完成的活动或过程的一种系统需求,它就是系统要投入的商业应用。用户需求(User
Requirement)
文档描述了用户使用产品必须要完成的任务，这在使用实例（Use
Case）文档或方案脚本（Scenario）说明中予以说明。功能需求(Functional
Requirement)定义了开发人员必须实现的软件功能，使得用户能完成他们的任务，从而满足了业务需求。而所谓特性(Feature)是指逻辑上相关的功能需求的集合，给用户提供处理能力并满足业务需求。<br/>

&nbsp;&nbsp;&nbsp;
系统分析阶段的活动则有如下几种（表1）,同时列举了其对应解决相应的关键问题。</P>
<P>&nbsp;</P>
<P>表1</P>
<P><br/>
分析阶段的活动<br/>
关键问题</P>
<P>收集信息
是否已经拥有了全部的信息来定义系统所必须完成的工作？<br/>
定义系统需求 需要系统做什么？<br/>
构建可行性的发现原型
可以证明此种技术能够实现想让它完成的那些功能吗？<br/>
是否已经构建出一些原型让用户能够完全理解新系统的潜在功能？</P>
<P>产生评估方案 创建系统的最好方案是什么？<br/>
与管理部门一起复查各种建议
是否应该继续设计和实现我们提出的系统？</P>
<P>&nbsp;</P>
<P>解决关键问题的方法，大致如下：</P>
<P>（1）
搞清楚系统相关者,通过组织结构图找系统角色,他们是系统的主要使用力量。</P>
<P>（2） 系统开发的分析阶段的目标是理解商业功能和获得系统需求。</P>
<P>（3）
在改正旧系统到新系统的转换过程中，关键是新系统。通过调查问卷，面谈去理解新系统的限制。通过复查现有文档，去理解信息的过程。通过研究商业过程和供应商，去理解新系统的功能。最终是为新系统开发出系统需求和模型。</P>
<P><br/>
以上的描述是一种系统分析的流程,下面介绍从需求角度看分析师的业务问题。</P>
<P>
需求开发依先后顺序可以分为：需求获取（Elicitation）、分析(Analysis)、编写规格说明（Specification）和验证（Verification）四个阶段。这些子项包括软件类产品中需求收集、评价、编写文档等所有活动。</P>
<P>需求开发活动包括以下几个方面：</P>
<P>（1） 确定产品所期望的用户类。</P>
<P>（2）获取每个用户类的需求。</P>
<P>（3） 了解实际用户任务和目标以及这些任务所支持的业务需求。</P>
<P>
（4）分析源于用户的信息，以区别用户任务需求、功能需求、业务规则、质量属性、建议解决方法和附加信息。</P>
<P>
（5）将系统级的需求分为几个子系统，并将需求中的一部份分配给软件组件。</P>
<P>（6）了解相关质量属性的重要性。</P>
<P>（7）商讨实施优先级的划分。</P>
<P>（8）将所收集的用户需求编写成规格说明和模型。</P>
<P>
（9）评审需求规格说明，确保对用户需求达到共同的理解与认识，并在整个开发小组接受说明之前将问题都要弄清楚。</P>
<P><br/>
&nbsp;&nbsp;&nbsp;
需求分析（Requirement
Analysis）包括提炼、分析和仔细审查已收集到的需求，以确保所有的风险承担者都明白其含义并找出其中的错误、遗漏或其它不足的地方。分析的目的在于开发出高质量的需求，这样你能做出实用的项目估算并可以进行设计、构造和测试。</P>
<P>&nbsp;&nbsp;&nbsp;
通常把需求中的一部分用多种形式来描述，如同时用文本和图形来描述。分析这些不同的视图将揭示出一些更深的问题，这是单一视图无法提供的。分析还包括与客户的交流以澄清某些混淆，并明确哪些需求是更为重要的。其目的是确保所有风险承担者尽早地对项目达成共识并对将来的产品有个相同而清晰的认识。下面是需求分析中经常使用的方法:</P>
<P>（1）绘制系统上下文示意图</P>
<P>
这种示意图是用于定义系统与系统外部实体间的界限和接口的简单模型。同时它也明确了通过接口的信息流和物质流。</P>
<P>（2）创建用户接口原型</P>
<P>
当开发人员或用户不能确定需求时，开发一个用户接口原型———个局部的可能实现——这样使得许多概念和可能发生的事更为直观明了。用户通过评价原型将使项目参与者能更好地相互理解所要解决的问题。注意要找出需求文档与原型之间的所有冲突之处。</P>
<P>（3）分析需求可行性</P>
<P>
在允许的成本、性能要求下，分析每项需求实施的可行性，明确与每项需求实现相联系的风险，包括与其它需求的冲突，对外界因素的依赖和技术障碍。</P>
<P>（4）确定需求的优先级别</P>
<P>
应用分析方法来确定使用实例、产品特性或单项需求实现的优先级别。以优先级为基础确定产品版本将包括哪些特性或哪类需求。当允许需求变更时，在特定的版本中加入每一项变更，并在那个版本计划中作出需要的变更。</P>
<P>（5）为需求建立模型</P>
<P>
需求的图形分析模型是软件需求规格说明极好的补充说明。它们能提供不同的信息与关系，以有助于找到不正确的、不一致的、遗漏的和冗余的需求。这样的模型包括数据流图、实体关系图、状态变换图、对话框图、对象类及交互作用图。</P>
<P>（6）创建数据字典</P>
<P>
数据字典是对系统用到的所有数据项和结构的定义，以确保开发人员使用统一的数据定义。在需求阶段，数据字典至少应定义客户数据项以确保客户与开发小组是使用一致的定义和术语。分析和设计工具通常包括数据字典组件。</P>
<P>（7）使用质量功能调配</P>
<P>质量功能调配(Quality Function
Deployment，QFD）是一种高级系统技术，它将产品特性、属性与对用户价值联系起来。该技术提供了一种分析方法以明确哪些是客户最为关注的特性。QFD将需求分为三类：期望需求，即客户或许并未提及，但如若缺少会让他们感到不满意；普通需求；兴奋需求，即实现了会给客户带去惊喜，但若未实现也不会受到责备。</P>
<P><br/>
&nbsp;&nbsp;&nbsp;
系统分析师需要掌握需求捕获、需求分析和需求确认方法,并且要有一定的实践经验,因为需求分析是门需要实践的学问。</P>
<P>&nbsp;&nbsp;&nbsp;
需求捕获的方法其实有多种,你可以熟悉每一种方法。通过文档概要、面谈、观察、原型、调查表、供应商调查、联合应用会议等等方法是可以获得需求的。但在实际中,你不必十八般武艺样样都要使出来,
本质上持续不断的捕获高质量的需求的方法只有一个，就是和业务人员打成一片,这样,不再是你去找需求,需求可能会来找你了,这是一种主动需求的方法,所以系统分析师一般都需要有良好的人际互动能力。</P>
<P>&nbsp;&nbsp;&nbsp;
当然,需求捕获还是有其自身的方法的, 要讲需求捕获必先谈到收集信息,
信息不足则“巧妇难为无米之炊”。其实这里有三个经典的问题,会是系统分析师经常用到的或提到的问题。由信息收集到需求捕获，再到需求分析是需求开发的中轴线,而能否收集到必要的有效的需求信息,
请仔细体会如下三个问题。</P>
<P>（1）商业过程和操作是什么，即你要干什么</P>
<P>
系统分析师核心是理解商业过程,一般用户只会对现状回答,但分析师要能识别在改进的系统中哪些要保留，哪些要删除。这个问题是沟通的第一步,回想当年笔者第一次就这样问用户：“你的流程是什么？你有什么问题”,何其愚也,从问用户的问题可以看出这个分析师是不是有经验。</P>
<P>（2
）商业过程应该怎样完成，即系统分析师该如何完成它,或者说需要哪些步骤</P>
<P>
用户谈的是老系统的完成办法,而系统分析师的核心是新系统应该如何支持这项功能,而不是在现有系统下如何执行。分析师重要的是超越现在,使新技术带来的商业处理方法更高效。<br/>

（３）需要什么样的信息，即为了完成商业过程，系统分析师要使用哪些信息，使用什么样的表单或报告。</P>
<P>
有价值的系统分析师有一套需求捕获的手法，有价值的系统分析师一定会从理论到实际仔细研究需求分析的过程。</P>
</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000am7.html#comment</comments>
            <pubDate>Fri, 31 Aug 2007 02:11:36 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000am7.html</guid>
        </item>
        <item>
            <title>检测远程URL是否存在的三种方法</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000aln.html</link>
            <description><![CDATA[<DIV>&nbsp;文章来源：<A HREF="http://blog.csdn.net/net_lover/archive/2005/11/30/540417.aspx"><FONT FACE="宋体">http://blog.csdn.net/net_lover/archive/2005/11/30/540417.aspx</FONT></A>
<P><FONT FACE="宋体">private void Page_Load(object sender,
System.EventArgs e)<br/>
{</FONT></P>
<P><FONT FACE="宋体">&nbsp;string url1 =
"http://dotnet.aspx.cc/";<br/>
&nbsp;string url2 =
"http://dotnet.aspx.cc/Images/logo.gif";<br/>
&nbsp;Response.Write("&lt;li&gt;方法1：");<br/>
&nbsp;Response.Write(url1 + " 存在：" +
UrlExistsUsingHttpWebRequest(url1).ToString());<br/>
&nbsp;Response.Write("&lt;li&gt;方法2：");<br/>
&nbsp;Response.Write(url1 + " 存在：" +
UrlExistsUsingSockets(url1).ToString());&nbsp;&nbsp;<br/>

&nbsp;Response.Write("&lt;li&gt;方法3：");<br/>
&nbsp;Response.Write(url1 + " 存在：" +
UrlExistsUsingXmlHttp(url1).ToString());</FONT></P>
<P><FONT FACE="宋体">&nbsp;Response.Write("&lt;li&gt;方法1：");<br/>
&nbsp;Response.Write(url2 + " 存在：" +
UrlExistsUsingHttpWebRequest(url2).ToString());<br/>
&nbsp;Response.Write("&lt;li&gt;方法3：");<br/>
&nbsp;Response.Write(url2 + " 存在：" +
UrlExistsUsingXmlHttp(url2).ToString());<br/>
}<br/></FONT></P>
<P><FONT FACE="宋体"><FONT FACE="宋体">private bool
UrlExistsUsingHttpWebRequest(string url)<br/>
{<br/>
&nbsp;try<br/>
&nbsp;{<br/>
&nbsp; System.Net.HttpWebRequest myRequest
=(System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);<br/>

&nbsp; myRequest.Method = "HEAD";<br/>
&nbsp; myRequest.Timeout = 100;<br/>
&nbsp; using(System.Net.HttpWebResponse res =
(System.Net.HttpWebResponse)myRequest.GetResponse())</FONT></FONT></P>
<P>&nbsp;&nbsp; {</P>
<P>&nbsp;&nbsp;&nbsp;
<FONT FACE="宋体"><FONT FACE="宋体">&nbsp; return
(res.StatusCode == System.Net.HttpStatusCode.OK);</FONT></FONT></P>
<P><FONT FACE="宋体"><FONT FACE="宋体">&nbsp;&nbsp; }<br/>
&nbsp;}<br/>
&nbsp;catch(System.Net.WebException we)<br/>
&nbsp;{<br/>
&nbsp;
System.Diagnostics.Trace.Write(we.Message);<br/>
&nbsp; return false;<br/>
&nbsp;}<br/>
}<br/>
<FONT FACE="宋体">private bool UrlExistsUsingXmlHttp(string
url)<br/>
{<br/>
&nbsp;//注意：此方法需要引用Msxml2.dll<br/>
&nbsp;MSXML2.XMLHTTP _xmlhttp = new
MSXML2.XMLHTTPClass();<br/>
&nbsp;_xmlhttp.open("HEAD",url,false,null,null);<br/>
&nbsp;_xmlhttp.send("");<br/>
&nbsp;return (_xmlhttp.status == 200 );<br/>
}<br/></FONT></FONT></FONT></P>
<P><FONT FACE="宋体">private bool UrlExistsUsingSockets(string
url)<br/>
{<br/>
&nbsp;if(url.StartsWith("http://")) url =
url.Remove(0,"http://".Length);<br/>
&nbsp;try<br/>
&nbsp;{<br/>
&nbsp; using(System.Net.IPHostEntry ipHost =
System.Net.Dns.Resolve(url))</FONT></P>
<P><FONT FACE="宋体">&nbsp; {<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return true;</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp; }<br/>
&nbsp;}<br/>
&nbsp;catch (System.Net.Sockets.SocketException
se)<br/>
&nbsp;{<br/>
&nbsp;
System.Diagnostics.Trace.Write(se.Message);<br/>
&nbsp; return false;<br/>
&nbsp;}<br/>
}</FONT></P>
</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(程序相关)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000aln.html#comment</comments>
            <pubDate>Thu, 30 Aug 2007 02:18:30 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000aln.html</guid>
        </item>
        <item>
            <title>ASP.NET 2.0中CSS失效的问题总结</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000all.html</link>
            <description><![CDATA[<DIV>文章来源：<A HREF="http://blog.csdn.net/net_lover/archive/2007/08/27/1760521.aspx"><FONT FACE="宋体">http://blog.csdn.net/net_lover/archive/2007/08/27/1760521.aspx</FONT></A></DIV>
<DIV><STRONG>&nbsp;<FONT FACE="宋体">ASP.NET
2.0中CSS失效的问题总结</FONT></STRONG></DIV>
<DIV><FONT FACE="宋体">1，CSS文件路径不正确<br/>
这个问题属于Web开发中的基础问题，一般采用相对路径会出现这样的问题，或者样式文件写在了母版页里面，在内容页与母版页不在同一级目录下时会出现这样的问题。此时你要清楚Web中相对路径的规则，如果你不清楚，可以采用绝对路径的写法试试就知道是不是路径的问题了。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">2，CSS规则写法错误<br/>
这个问题谁也帮不你，只能自己学习CSS的相关知识了。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">3，文件编码问题<br/>
有时候，CSS样式放在aspx文件里有效，而放在独立的文件中无效，这样的问题如果不是路径问题，则就是编码问题造成的，可以将CSS文件用记事本打开，再另存为ANSI格式或者UTF-8格式即可。</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体">4，权限问题<br/>
这种情况常见的现象是登录之前样式无效，登录之后才有效，这是典型的权限问题造成的。由于web.config配置了所有文件不允许匿名访问，才会出现这样的问题，解决方法就是将&lt;location&gt;标记将样式文件配置为允许匿名访问。例如：</FONT></DIV>
<DIV><FONT FACE="宋体">&lt;configuration&gt;<br/>
&nbsp;&nbsp; &lt;location
path="允许匿名访问的文件夹名称或者文件路径"&gt;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;system.web&gt;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;authorization&gt;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;allow users="?"/&gt;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/authorization&gt;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/system.web&gt;<br/>
&nbsp;&nbsp; &lt;/location&gt;<br/>
&lt;/configuration&gt;<br/></FONT></DIV>
<DIV><FONT FACE="宋体"><FONT FACE="宋体">5，单击按钮样式失效<br/>
这种情况最典型的原因是单击按钮事件里有类似Response.Write这样的语句，由于ASP.NET
2.0默认采用http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd文档类型定义，它就要求在&lt;!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;的前面不能有任何输出。这种问题的解决方法是采用ClientScriptManager输出，或者采用Literal控件输出内容。</FONT></FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体"><FONT FACE="宋体">6，在ASP.NET
1.x里面起作用的样式到ASP.NET 2.0里面失效<br/>
这种问题一般仍然是xhtml1造成的，由于<A HREF="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</A>的样式规则与以前的不同，如要加单位，例如width:200;现在要写成width:200px;这种问题的解决方法就是要明确加上单位</FONT></FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT FACE="宋体"><FONT FACE="宋体">7，脚本设置的样式无效<br/>
由于xhtml1.DTD要求有单位，因此在设置对象样式的数值时，仍然要加上单位，如obj.style.width
=
"200px"。下面的代码在Firefox了是无效的（不要抱怨Firefox麻烦）</FONT></FONT></DIV>
<DIV><FONT FACE="宋体"><FONT FACE="宋体">&lt;!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;<br/>
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br/>
&lt;head&gt;<br/>
&nbsp; &lt;script type="text/javascript"&gt;<br/>
&nbsp; //&lt;![CDATA[<br/>
&nbsp; function SetHeight()<br/>
&nbsp; {<br/>
&nbsp;&nbsp;&nbsp;
document.getElementById("x").style.height="200"<br/>
&nbsp; }<br/>
&nbsp; //]]&gt;<br/>
&nbsp; &lt;/script&gt;<br/>
&lt;/head&gt;<br/>
&lt;body&gt;<br/>
&lt;div id="x"
style="background:#DDD;height:auto;"&gt;测试&lt;/div&gt;<br/>
&lt;input type="button" value="设置" onclick="SetHeight()"
/&gt;<br/>
&lt;/body&gt;<br/>
&lt;/html&gt;</FONT></FONT></DIV>
<DIV><FONT FACE="宋体"><FONT FACE="宋体">尽管上面在IE中正常，但在Firefox里面则会出现问题。正确写法为</FONT></FONT></DIV>
<DIV><FONT FACE="宋体">document.getElementById("x").style.height="200px"</FONT></DIV>
]]></description>
            <author>klvein</author>
            <category>KM(程序相关)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000all.html#comment</comments>
            <pubDate>Thu, 30 Aug 2007 01:44:56 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000all.html</guid>
        </item>
        <item>
            <title>屏蔽所有的Javascript异常</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000ah7.html</link>
            <description><![CDATA[<DIV>&nbsp;<FONT FACE="宋体">//屏蔽所有的Javascript异常<br/>
&nbsp;window.onerror = function(){return
true};</FONT></DIV>
]]></description>
            <author>klvein</author>
            <category>KM(程序相关)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000ah7.html#comment</comments>
            <pubDate>Tue, 21 Aug 2007 01:47:35 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000ah7.html</guid>
        </item>
        <item>
            <title>ASP.NET 2.0客户端回调的实现分析</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000aal.html</link>
            <description><![CDATA[<DIV>
<P>&nbsp;</P>
<P><STRONG>JS_Scriptblock:</STRONG></P>
<P><FONT FACE="宋体">function
CallServer(inputcontrol,context)<br/>
&nbsp;&nbsp;&nbsp; {<br/>
　&nbsp;&nbsp;&nbsp;
//回调还没有处理完全时其预先加载的显示值<br/>
　&nbsp;&nbsp;&nbsp;
context.innerHTML = "加载中......";<br/>
　&nbsp;&nbsp;&nbsp;
//为你在文本框中输入的信息，并且arg在这里就是将其值传递到<br/>
　&nbsp;&nbsp;&nbsp;
//RaiseCallbackEvent(String
eventArgument)方法对应的eventArgument中<br/>
　&nbsp;&nbsp;&nbsp; arg =
inputcontrol.value;</FONT></P>
<P><FONT FACE="宋体">　&nbsp;&nbsp;&nbsp;
//获取一个对客户端函数的引用；调用该函数时，将启动一个对服务器端事件的客户端回调。<br/>

　&nbsp;&nbsp;&nbsp; &lt;%=
ClientScript.GetCallbackEventReference(this, "arg",
"ReceiveServerData", "context")%&gt;;<br/>
&nbsp;&nbsp;&nbsp; }<br/>
&nbsp;&nbsp;&nbsp;<br/>
&nbsp;&nbsp;&nbsp; function
ReceiveServerData(result,context)<br/>
&nbsp;&nbsp;&nbsp; {<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
context.innerHTML = result;<br/>
&nbsp;&nbsp;&nbsp; }</FONT></P>
<P>&nbsp;</P>
<P><STRONG>HTML_ScriptBlock:</STRONG></P>
<P><FONT FACE="宋体">&nbsp;&lt;asp:TextBox
ID="txtEnter" runat="server"
&gt;&lt;/asp:TextBox&gt;&amp;nbsp;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;input id="btnSubmit" type="button" value="提交"
onclick="CallServer(txtEnter,lblShow)" /&gt;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;asp:Label ID="lblShow"
runat="server"&gt;&lt;/asp:Label&gt;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;asp:Button ID="Button1" runat="server" OnClick="Button1_Click"
Text="Button" /&gt;</FONT></P>
<P>&nbsp;</P>
<P>C#_ScriptBlock:</P>
<P><FONT FACE="宋体">public partial class ClientCallBack_CallBack :
System.Web.UI.Page,ICallbackEventHandler</FONT></P>
<P>.......</P>
<P><FONT FACE="宋体">//引发回调事件处理<br/>
&nbsp;&nbsp;&nbsp; public void
RaiseCallbackEvent(string eventArgument)<br/>
&nbsp;&nbsp;&nbsp; {<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//"eventArgument"为从客户端的JavaScript传递过来的参数<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
result = "从服务器端返回的内容：" + eventArgument +
this.ViewState["test"].ToString();<br/>
&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;
//回传回调结果<br/>
&nbsp;&nbsp;&nbsp; public
string GetCallbackResult()<br/>
&nbsp;&nbsp;&nbsp; {<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return result;<br/>
&nbsp;&nbsp;&nbsp; }</FONT></P>
<P>&nbsp;</P>
<P><STRONG>方法说明：</STRONG></P>
<P>public string GetCallbackEventReference (Control control,string
argument,string clientCallback,string context)</P>
<P><FONT FACE="宋体">参数：</FONT></P>
<P><FONT FACE="宋体">control 处理客户端回调的服务器
Control。该控件必须实现 ICallbackEventHandler 接口并提供
RaiseCallbackEvent 方法。&nbsp;<br/>
argument&nbsp;
从客户端脚本传递一个参数到服务器端的RaiseCallbackEvent
方法。&nbsp;<br/>
clientCallback&nbsp;
一个客户端事件处理程序的名称，该处理程序接收服务器端事件返回的结果。<br/>

context
启动回调之前在客户端的客户端脚本信息。脚本的结果传回给客户端事件处理程序。&nbsp;<br/>

返回值 调用客户端回调的客户端函数的名称。</FONT></P>
<P>&nbsp;</P>
<P><FONT FACE="宋体"><br/>
ClientScriptManager.GetCallbackEventReference (Control, String,
String, String)
获取一个对客户端函数的引用；调用该函数时，将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本和上下文。<br/>

ClientScriptManager.GetCallbackEventReference (Control, String,
String, String, Boolean)
获取一个对客户端函数的引用；调用该函数时，将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本、上下文和布尔值。<br/>

ClientScriptManager.GetCallbackEventReference (Control, String,
String, String, String, Boolean)
获取一个对客户端函数的引用；调用该函数时，将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本、上下文、错误处理程序和布尔值。<br/>

ClientScriptManager.GetCallbackEventReference (String, String,
String, String, String, Boolean)
获取一个对客户端函数的引用；调用该函数时，将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的目标、参数、客户端脚本、上下文、错误处理程序和布尔值。
我们就整个程序作个系统的说明，并且列出前台的页面代码和后台的逻辑代码，这样可以使得你对程序有个直观的理解。<br/>
</FONT></P>
<P><br/>
&nbsp;</P>
</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(程序相关)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000aal.html#comment</comments>
            <pubDate>Sat, 11 Aug 2007 11:33:28 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000aal.html</guid>
        </item>
        <item>
            <title>几个不常用的HTML标记</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000aa5.html</link>
            <description><![CDATA[<DIV>&nbsp;<FONT FACE="宋体">几个不常用的HTML标记</FONT></DIV>
<DIV>
<P><FONT FACE="宋体"><br/>
HTML中几个Tag比较有用，平时大家用得比较少，而且是符合W3C
XHTML标准的。</FONT></P>
<P>1. Label</P>
<P>Label是用来标记Input元素的提示的。例如：<br/>
&lt;label for="id_name"&gt;Name&lt;/label&gt;&lt;br /&gt;<br/>
&lt;input type="text" name="name" id="id_name" size="20"/&gt;</P>
<P>Label的“For”属性要和Input元素的ID相一致。</P>
<P>
好处：点击提示文字，就自动Focus对应的输入元素。对于Radio，Checkbox这类点击区域特别小的控件特别有用：</P>
<P><FONT FACE="宋体">Color:&lt;br /&gt;<br/>
&lt;input type="checkbox" name="color" id="color_r"
value="red"&gt;&lt;label for="color_r"&gt; red&lt;/label&gt;&lt;br
/&gt;<br/>
&lt;input type="checkbox" name="color" id="color_g"
value="green"&gt;&lt;label for="color_g"&gt;
green&lt;/label&gt;&lt;br /&gt;<br/>
&lt;input type="checkbox" name="color" id="color_b"
value="blue"&gt;&lt;label for="color_x"&gt;
blue&lt;/label&gt;&lt;br /&gt;<br/>
&lt;!--如果For和ID不匹配，点击文字是没有用的--&gt;</FONT></P>
<P>&nbsp;</P>
<P><FONT FACE="宋体">2. FieldSet &amp; Legend</FONT></P>
<P><FONT FACE="宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
FieldSet用来明确把一组Input控件归成一组（相当于VB/VC里面的Group控件），而Legend则是组的标题(相当于Group控件的标题)。
例如：</FONT></P>
<P><FONT FACE="宋体">&lt;fieldset style="width:20%"&gt;<br/>
&lt;legend&gt;Person&lt;/legend&gt;<br/>
&lt;label for="name"&gt;Name&lt;/label&gt;&lt;input type="text"
id="name" /&gt;<br/>
&lt;fieldset&gt;<br/>
&lt;legend&gt;Gender&lt;/legend&gt;<br/>
&lt;input type="radio" name="gender" id="male" /&gt;&lt;label
for="male"&gt;Male&lt;/label&gt;&lt;br&gt;<br/>
&lt;input type="radio" name="gender" id="female" /&gt;&lt;label
for="female"&gt;Female&lt;/label&gt;<br/>
&lt;/fieldset&gt;</FONT></P>
</DIV>
<P>&nbsp;</P>
<P><FONT FACE="宋体"><FONT FACE="宋体"><FONT FACE="宋体">3.
Optgroup</FONT></FONT></FONT></P>
<P><FONT FACE="宋体">用于Select里面的option的分组。例如：<br/>
&lt;select name="age"&gt;<br/>
&lt;optgroup label="baby"&gt;<br/>
&lt;option&gt;0-2&lt;/option&gt;<br/>
&lt;option&gt;3-5&lt;/option&gt;<br/>
&lt;/optgroup&gt;<br/>
&lt;optgroup label="kid"&gt;<br/>
&lt;option&gt;6-10&lt;/option&gt;<br/>
&lt;option&gt;10-15&lt;/option&gt;<br/>
&lt;/optgroup&gt;<br/>
&lt;optgroup label="adult"&gt;<br/>
&lt;option&gt;16-30&lt;/option&gt;<br/>
&lt;option&gt;31-40&lt;/option&gt;<br/>
&lt;option&gt;41-60&lt;/option&gt;<br/>
&lt;/optgroup&gt;<br/>
&lt;/select&gt;</FONT></P>
<P><br/>
&lt;/fieldset&gt;</P>
<P>&nbsp;</P>
]]></description>
            <author>klvein</author>
            <category>KM(程序相关)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000aa5.html#comment</comments>
            <pubDate>Fri, 10 Aug 2007 06:02:03 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000aa5.html</guid>
        </item>
        <item>
            <title>Javascript小技巧</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a88.html</link>
            <description><![CDATA[<DIV>&nbsp;文章来源:<A HREF="http://www.cnblogs.com/ttyp/archive/2004/11/15/63900.aspx"><FONT FACE="宋体">http://www.cnblogs.com/ttyp/archive/2004/11/15/63900.aspx</FONT></A></DIV>
]]></description>
            <author>klvein</author>
            <category>KM(程序相关)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a88.html#comment</comments>
            <pubDate>Tue, 07 Aug 2007 02:28:51 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a88.html</guid>
        </item>
        <item>
            <title>【重构与模式】第八章 泛化&gt;&gt;提取Adapter</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a79.html</link>
            <description><![CDATA[<DIV>提取Adapter</DIV>
<DIV>&nbsp;</DIV>
<DIV>
意图：一个类适配了多个版本的组件、类库、API或其它实体。为组件、类库、API或其它实体的每个版本提取一个Adapter。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
动机：对于所需要支持的东西的每一个版本，创建一个单独的类。这个类名甚至可以包含它所支持的版本号，以便于显示地指出它所支持地版本。这些类就是Adapter。Adapter可以使客户代码很容易地从类库或API的一个版本转入另一个版本。并且，程序员通常依赖于运行时信息，使用正确的Adapter来配置他们的程序。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点与缺点：</DIV>
<DIV>＋隔离了不同版本组件、类库或API之间的不同之处。</DIV>
<DIV>＋使类只负责适配代码的一个版本。</DIV>
<DIV>＋避免频繁地修改代码。</DIV>
<DIV>
－如果某个重要的行为在Adapter中不可用的话，那么客户代码将无法执行这一重要行为。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>1、识别出负担过重的适配器，即适配了太多版本的类。</DIV>
<DIV>
2、针对负担过重的适配器所支持的多个版本中的一个版本，应用提炼子类重构或提炼类重构，产生一个新的适配器。把只用于这个版本的实例变量和方法复制或搬移到新的适配器中。</DIV>
<DIV>3、重复步骤2直到负担过重的适配器重不再含有版本为止。</DIV>
<DIV>4、应用上移方法和形成Template
Method之类的重构，去除新适配器中的重复代码。</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a79.html#comment</comments>
            <pubDate>Sun, 05 Aug 2007 07:22:56 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a79.html</guid>
        </item>
        <item>
            <title>【重构与模式】第八章 泛化&gt;&gt;通过Adapter统一接口</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a77.html</link>
            <description><![CDATA[<DIV>通过Adapter统一接口</DIV>
<DIV>&nbsp;</DIV>
<DIV>
意图：客户代码与两个类交互，其中的一个类具有首选的接口。用一个Adapter统一接口。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
动机：当代码原本可以通过统一的接口与不同的类交互，而出于某种原因，实际代码并非如此的时候，坏味异曲同工的类就出现了，解决这种问题的一个简单的方法是重命名或搬移方法，直到接口相同。如果无法实现这种改动，就可能需要考虑实现一个Adapter了。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点和缺点：</DIV>
<DIV>
＋使客户代码可以通过相同的接口与不同的类交互，从而去除或减少了重复代码。</DIV>
<DIV>
＋使客户代码可以通过公共的接口与多个对象交互，从而简化了客户代码。</DIV>
<DIV>＋统一了客户代码与不同的类的交互方式。</DIV>
<DIV>－当类的接口可以改变的时候，会增加设计的复杂度。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>
1、客户代码更愿意使用一个类的接口，而不是另一个，而且，客户代码希望可以通过一个公共的接口与两个类交互。在具有客户代码首选接口的类上应用提炼接口重构，生成一个公共接口。更新这个类中所有接收自身类型为参数的方法，使其参数类型变为这个公共接口。</DIV>
<DIV>
2、在使用被适配者的客户类中，应用提炼类重构产生一个原生适配器。</DIV>
<DIV>
3、把客户类中所有类型为被适配者的字段、本地变量或参数的类型都更新为适配器。这包括被适配者的客户代码先从适配器获得被适配者的引用，然后再调用被适配者的方法。</DIV>
<DIV>
4、对任何客户代码调用相同被适配者方法的地方，应用提炼方法重构，以便产生一个被适配者的调用方法。</DIV>
<DIV>
5、在被适配者调用方法上应用搬移方法重构，把它从客户代码搬移到适配器中，客户代码中每处对这个被适配者方法的调用现在都应该通过这个适配器。</DIV>
<DIV>6、更新适配器，使其正式地“实现”这个公共接口。</DIV>
<DIV>
7、更新客户代码，把所有类型为适配器地字段、本地变量和参数都改为使用公共接口类型。</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a77.html#comment</comments>
            <pubDate>Sun, 05 Aug 2007 03:32:56 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a77.html</guid>
        </item>
        <item>
            <title>【重构与模式】第八章 泛化&gt;&gt;用Oberver替换硬编码的通知</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a76.html</link>
            <description><![CDATA[<DIV>用Observer替换硬编码的通知</DIV>
<DIV>&nbsp;</DIV>
<DIV>
意图：子类通过硬编码来通知另一个类的一个实例。去除这些子类，并使其超类能够通知一个或多个实现了Observer接口的类。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
动机：Observer模式的每次实现都会产生一个主题（作为通知源的类）与其观察者之间的松耦合。Observer接口使这种松耦合成为可能。想要接收新信息的通知，类只需实现Observer接口，并把自己注册到一个主题。当发生改变时，主题会根据它所包含的实现了Observer接口的实例的集合依次通知这些实例。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点和缺点：</DIV>
<DIV>＋使主题及观察者访问松散耦合。</DIV>
<DIV>＋支持一个或多个观察者。</DIV>
<DIV>－当硬编码的通知已经足够的时候，会增加设计的复杂度。</DIV>
<DIV>－当出项串联通知的时候，会增加代码的复杂度。</DIV>
<DIV>
－当观察者没有从它们的主题中被删除的时候，可能会造成内存泄漏。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>
1、如果一个通知者代表它的接收者执行定制的行为，而不是执行单纯的通知逻辑，应用搬移到通知者的接收者中。</DIV>
<DIV>
2、在接收者上应用提炼接口重构，只选择被它的通知者调用的方法，产生观察者接口。如果其他通知者会调用不在观察者接口中的方法，把这些方法添加到观察者接口中，这样它就可以支持所有接收者了。</DIV>
<DIV>
3、使每个接收者都实现观察者接口。然后，使每个通知者都只通过观察者接口与它的接收者交互。</DIV>
<DIV>
4、选择一个通知者，在其通知方法上应用上移方法重构。这包含上移通知者的观察者接口引用，以及设置引用的代码。</DIV>
<DIV>
5、更新每个通知者的观察者，使它们注册到主题并与其交互，而不是通知者，然后删除通知者。</DIV>
<DIV>
6、重构这个主题，使它包含观察者的一个集合，而不是仅仅一个观察者。</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a76.html#comment</comments>
            <pubDate>Sun, 05 Aug 2007 02:43:55 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a76.html</guid>
        </item>
        <item>
            <title>【重构与模式】第八章 泛化&gt;&gt; 用Composite替换一/多之分</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a73.html</link>
            <description><![CDATA[<DIV>用Composite替换一/多之分</DIV>
<DIV>&nbsp;</DIV>
<DIV>
意图：类使用不同的代码处理单一对象与多个对象。用Composite能够产生既可以处理单一对象又可以处理多个对象的代码。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
动机：如果一个类含有两个几乎一样的方法，唯一的区别就是一个用来处理单一对象，一个用来处理对象的集合，那么一/多之分就出现了。</DIV>
<DIV>
用Composite替换一/多之分可以去除重复代码，统一客户代码的调用，还支持对象树的处理。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点和缺点：</DIV>
<DIV>＋去除与处理一个或多个对象相关联的重复代码。</DIV>
<DIV>＋提供了处理一个或多个对象的统一方法。</DIV>
<DIV>＋支持处理多个对象的更丰富的方法。</DIV>
<DIV>
－可能会在Composite的构造过程中要求类型安全的运行时检查。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>
1、多对象方法接收一个集合作为参数。创建一个新类，使它的一个构造函数可以接收集合，并为集合定义访问方法。</DIV>
<DIV>
2、对多对象方法中与集合相关的代码应用提炼方法重构。把提炼出来的方法声明为公共方法，然后，在提炼出来的方法上引用搬移方法重构，把它搬移到组合类中。3、多对象几乎和单一对象方法一摸一样了，主要的区别是，多对象方法会实例化组合类。</DIV>
<DIV>
4、修改多方法对象方法，使其只包含一行代码：调用单一对象方法，并把组合类实例作为参数传递给这个方法。需要使组合类与单一对象方法中使用的类型共享相同的接口或超类。</DIV>
<DIV>
5、因为多对象方法现在只包含一行代码，所以可以使用将方法内联化重构使其内联化。</DIV>
<DIV>6、对组合类应用封装集合重构。</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a73.html#comment</comments>
            <pubDate>Sun, 05 Aug 2007 02:02:51 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a73.html</guid>
        </item>
        <item>
            <title>【重构与模式】第八章 泛化&gt;&gt;提取Composite</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a6q.html</link>
            <description><![CDATA[<DIV>提取Composite</DIV>
<DIV>&nbsp;</DIV>
<DIV>
意图：一个类层次结构中的多个子类实现了同一个Composite。提取一个实现该Composite的超类。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
动机：在提炼超类重构中，如果两个或多个类拥有相似的特性，就应该把这些共有的特性搬移到一个超类中。当相似属性是一个Composite时，应该把它搬移到超类中去。</DIV>
<DIV>
类层次结构中的子类往往会存储其他类的集合，并含有报告这些类信息的方法。当这些被存储的类恰好在同一个类层次结构中时，就很有可能需要通过重构到Composite去除大量的重复代码。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点和缺点：</DIV>
<DIV>＋去除重复的类存储逻辑和类处理逻辑。</DIV>
<DIV>＋能够有效地表达类处理逻辑的可继承性。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>
1、创建一个组合，它是在重构之后会成为一个Composite的类。适当的命名这个类，使其能反映出它所存储的类的类型。</DIV>
<DIV>2、把每个含有子结点的类声明为组合类的子类。</DIV>
<DIV>
3、在含有子结点的类中，找出这样的类处理方法，它在所有含有子结点的类中被完全复制或部分复制。</DIV>
<DIV>
4、对含有子结点的类中其他的包含完全重复和部分重复代码的类处理方法重复步骤3。</DIV>
<DIV>
5、检查每个含有子结点的类的每段客户代码，考虑现在是否可以通过组合类的结构与含有子结点的类交互。如果可以，就改为使用组合类接口。</DIV>
<DIV>&nbsp;</DIV>
]]></description>
            <author>klvein</author>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a6q.html#comment</comments>
            <pubDate>Sat, 04 Aug 2007 08:15:28 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a6q.html</guid>
        </item>
        <item>
            <title>【重构与模式】第八章 泛化&gt;&gt;形成Template Method</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a6l.html</link>
            <description><![CDATA[<DIV>形成Template Method</DIV>
<DIV>&nbsp;</DIV>
<DIV>
意图：子类中的两个方法以相同的顺序执行相似的步骤，但是步骤并不完全相同。通过把这些步骤提取成具有相同签名的方法来泛化这两个方法，然后上移这些泛化方法，形成Template
Method。</DIV>
<DIV>&nbsp;</DIV>
<DIV>动机：Template
Method“一次性实现了一个算法的不变部分，并将可变的行为留给子类来实现”。当不变的和可变的行为在方法的子类实现中混合在一起的时候，不变的行为就会在子类中重复出现。通过把这些行为搬移到单一的地方，重构到Template
Method可以帮助子类摆脱重复的不变的行为纠缠：超类中的方法中的泛化算法。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点和缺点：</DIV>
<DIV>＋通过把不变行为搬移到超类，去除子类中的重复代码。</DIV>
<DIV>＋简化并有效的表达了一个通用算法的步骤。</DIV>
<DIV>＋允许子类很容易地定制一个算法。</DIV>
<DIV>
－当为了生成算法，子类必须实现很多方法的时候，会增加设计的复杂度。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>
1、在一个类层次结构中，找到一个相似的方法。在相似的方法上应用组合方法重构，提取出同一方法。</DIV>
<DIV>2、应用上移方法重构，把同一方法上移到超类中。</DIV>
<DIV>
3、为了为相似方法的每个版本产生相同的方法体，在每个唯一方法上应用重命名方法重构，直到每个子类中额相似方法相同为止。</DIV>
<DIV>
4、如果相似方法在每个子类中还没有一个相同的签名，应用重命名方法重构产生这个签名。</DIV>
<DIV>
5、在相似方法上应用上移方法重构，在超类中为每个唯一方法定义抽象方法。</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a6l.html#comment</comments>
            <pubDate>Sat, 04 Aug 2007 07:48:41 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a6l.html</guid>
        </item>
        <item>
            <title>【重构与模式】第七章 简化&gt;&gt;用Command替换条件调度程序</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a6j.html</link>
            <description><![CDATA[<DIV>用Command替换条件调度程序</DIV>
<DIV>&nbsp;</DIV>
<DIV>
意图：条件逻辑用来调度请求和执行操作。为每个动作创建一个Command。把这些Command存储在一个集合中，并用获取及执行Command的代码替换条件逻辑。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
动机：许多系统都会收到、发送并处理请求。条件调度程序是一条条件语句，它用来执行请求的发送和处理。有些条件调度程序很适合它们要完成的任务，有些则并不适合。</DIV>
<DIV>
适合任务的条件调度程序往往只是把少量的请求发送到少量的处理逻辑中。这种调度程序的代码往往可以在一屏内显示我们不需要滚动屏幕。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点和缺点:</DIV>
<DIV>＋提供了用统一方法执行不同行为的简单机制。</DIV>
<DIV>＋允许在运行时改变所处理的请求，以及如何处理请求。</DIV>
<DIV>＋仅仅需要很少的代码实现。</DIV>
<DIV>－当条件调度程序已经足够的时候，会增加设计的复杂度。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>
1、在包含条件调度程序的类中找到处理请求的代码，在这段代码上应用提炼方法重构，直到产生执行该代码行为的执行方法为止。</DIV>
<DIV>
2、重复步骤1，把所有剩余的请求处理代码提炼到各自的执行方法中。</DIV>
<DIV>
3、在每个执行方法上应用提炼类重构，产生处理请求的具体命令。</DIV>
<DIV>
4、定义一个命令，即声明了与每个具体命令相同的执行方法的接口或抽象类。</DIV>
<DIV>
5、使每个具体命令都实现或继承这个命令，并用命令类型更新所有使用具体命令的客户代码。</DIV>
<DIV>
6、在包含条件调度程序的类中，定义并组装一个命令映射，这个映射包含每个具体命令，并用唯一标识符作为主键，在运行时可以用这个主键获取命令。</DIV>
<DIV>
7、在包含条件调度程序的类中，把调度程序请求的条件代码替换为获取正确的具体命令并调用其执行方法的代码。</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a6j.html#comment</comments>
            <pubDate>Sat, 04 Aug 2007 06:53:59 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a6j.html</guid>
        </item>
        <item>
            <title>【重构与模式】第七章 简化&gt;&gt;用Composite替换隐含树</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a6i.html</link>
            <description><![CDATA[<DIV>用Composite替换隐含树</DIV>
<DIV>&nbsp;</DIV>
<DIV>
意图：用原生表示法隐含地形成树结构。用Composite替换这个原生表示法。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
动机：基于数据地隐含树，往往要忍受构造隐式树的代码与如何表示树的代码之间的耦合之苦。重构实现Composite可以解开这种耦合；然而，重构后的客户代码又会与Composite耦合在一起。有时，需要通过另外一个间接层来解耦合。这是就需要应用用Builder封装Composite重构。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点和缺点：</DIV>
<DIV>＋封装重复的指令，如格式化、添加或删除结点。</DIV>
<DIV>＋提供了处理相似逻辑增长的一般性方法。</DIV>
<DIV>＋简化了客户代码的构造职责。</DIV>
<DIV>－当构造隐式树更简单的时候，会增加设计的复杂度。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>
1、识别隐式叶子，即隐式树中可以被建模为新类的部分。这个新类就是叶子结点。应用提炼类或类似重构创建这个新的叶子结点类，或者使用测试驱动开发－－针对具体情况，选择两者中更简单的方法。</DIV>
<DIV>
2、用叶子结点的实例替换隐式叶子的每一次使用，这样，隐式树就不再依赖于隐式叶子而依赖于叶子结点了。</DIV>
<DIV>
3、对隐式树中其他可以表示为隐式叶子的部分重复步骤1和步骤2。确保创建出的所有叶子结点都共享一个统一的接口。可以应用提炼超类重构或提炼接口重构来生成这个接口。</DIV>
<DIV>
4、识别隐式双亲，即隐式树中作为隐式叶子双亲的部分。隐式双亲将要变具体情况，选择两者中更简单的那个方法。</DIV>
<DIV>
5、用双亲结点的实例替换隐式双亲的每一次使用，并用正确的叶子结点实例进行配置。</DIV>
<DIV>
6、对其他隐式双亲重复步骤4和步骤5。当且仅当隐式双亲支持的情况下，才允许为双亲结点添加双亲结点。</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a6i.html#comment</comments>
            <pubDate>Sat, 04 Aug 2007 06:35:29 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a6i.html</guid>
        </item>
        <item>
            <title>【重构与模式】第七章 简化&gt;&gt;用State替换状态改变条件语句</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a6e.html</link>
            <description><![CDATA[<DIV>用State替换状态改变条件语句</DIV>
<DIV>&nbsp;</DIV>
<DIV>
意图：控制一个对象状态转换的条件表达式过于复杂。用处理特殊状态和状态转换的State类替换条件语句。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
动机：把状态改变的逻辑从类中去除，并搬移到表示不同状态的一系列类中，可以产生更简单的设计，它提供了观察状态间转换的更好的模型图。另一方面，如果类中的状态转换逻辑很容易理解，就不需要重构到State模式。</DIV>
<DIV>
在重构到State模式前，考虑简单的重构能否能够帮助我们整理状态转换条件逻辑是很有好处的。如果不能，重构到State模式是可以帮助我们去除或减少许多条件逻辑，产生更易于理解和扩展的代码。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点和缺点：</DIV>
<DIV>＋减少或去除状态改变的条件逻辑。</DIV>
<DIV>＋简化了复杂的状态改变逻辑。</DIV>
<DIV>＋提供了观察状态改变逻辑的很好的模型图。</DIV>
<DIV>－当状态转换逻辑已经易于理解的时候，会增加设计的复杂度。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>
1、上下文类是包含原始状态字段的类，在状态转换过程中，原始状态字段会被一系列常量赋值或与之比较。在原始状态字段上应用用类替换类型代码重构，这样它的类型就变成了一个类。我们称这个新类为状态朝类。</DIV>
<DIV>
2、状态超类中的每个常量现在都引用着状态超类的一个实例。应用提炼子类重构，为每个常量产生一个子类，然后更新状态超类中的常量，使它们引用相应的子类实例。</DIV>
<DIV>
3、在上下文类中找出根据状态转换逻辑来修改最少的前提下使这个新方法可以运行。</DIV>
<DIV>
4、选择上下文类能够进入状态，然后识别出状态朝类中的哪些方法会使这个状态转换到其他状态。</DIV>
<DIV>
5、删除每个步骤3中被复制到状态朝类的方法的方法体，为每个方法产生一个空实现。</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a6e.html#comment</comments>
            <pubDate>Sat, 04 Aug 2007 03:29:18 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a6e.html</guid>
        </item>
        <item>
            <title>【重构与模式】第七章 简化&gt;&gt;将装饰模式搬移到Decorator</title>
            <link>http://blog.sina.com.cn/s/blog_4ab2632701000a66.html</link>
            <description><![CDATA[<DIV>
意图：代码向类的核心职责提供装饰功能。将装饰代码搬移到Decorator。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
动机：把每个装饰功能放在单独的类中，并让这个类包装它所要装饰的对象，因此当需要执行特殊行为时，客户代码就可以在运行时使用装饰功能包装对象。</DIV>
<DIV>&nbsp;</DIV>
<DIV>优点和缺点：</DIV>
<DIV>＋把装饰功能从类中搬移去除，从而简化子类。</DIV>
<DIV>＋有效地把类地核心职责和装饰功能区分开来。</DIV>
<DIV>＋可以去除几个相关类中重复地装饰逻辑。</DIV>
<DIV>－改变了被装饰对象地对象类型。</DIV>
<DIV>－会使代码变得更难理解和调试。</DIV>
<DIV>
－当Decorator组合产生负面影响的时候，会增加设计的复杂度。</DIV>
<DIV>&nbsp;</DIV>
<DIV>做法：</DIV>
<DIV>
1、确定或创建包装类型、接口或类，它声明了客户代码需要的被修饰类的公共方法。</DIV>
<DIV>
2、找到为被修饰类添加装饰功能的条件逻辑，并应用用多态替换条件式重构去除这些逻辑。</DIV>
<DIV>
3、步骤2产生了被修饰类的一个或多个子类。应用用委托替代继承重构把这些子类转换成委托类。</DIV>
<DIV>
4、每个委托类都用被修饰类的新建实例对自己的委托字段进行了赋值。确保这个赋值逻辑语句在委托类的构造函数。然后提取参数重构提取赋值语句中实例化被修饰类的部分。如果可能的话，重复应用移除构造函数中不必要的参数。</DIV>
]]></description>
            <author>klvein</author>
            <category>KM(学习笔记)</category>
            <comments>http://blog.sina.com.cn/s/blog_4ab2632701000a66.html#comment</comments>
            <pubDate>Fri, 03 Aug 2007 14:04:36 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_4ab2632701000a66.html</guid>
        </item>
    </channel>
</rss>
