敏捷开发的必要技巧:保持代码简洁
浏览:43日期:2023-03-17
内容: 示例 这是一个会议管理系统。它用来管理所有参会者的信息。刚开始的时候,我们只需要记录每个参会者的ID(这是会议组织者分配的),姓名,电话和地址就行。于是,我们写了如下的代码: class Participant { String id; String name; String telNo; String address; } class ConferenceSystem { Participant participants[] } 接着,新的需求来了:现在每个参会者都可以让组织者帮忙预订酒店,所以我们要记录下他想预订的酒店名,入住日期,离开日期,房间类型(单人房或者双人房)。于是我们又扩充成如下的代码: class Participant { String id; String name; String telNo; String address; boolean bookHotelForHim; String hotelName; Date checkInDate; Date checkOutDate; boolean isSingleRoom; void setHotelBooking(String hotelName, Date checkInDate, ...) { ... } } 接着,又有一个新的需求来了:参会者可以参加不同的研讨会,所以我们要记录下参会者参加的研讨会。对于他要参加的每一场研讨会,我们还要记录下他的登记时间,同时他还需要什么翻译设备。于是代码又扩充成: class Participant { String id; String name; String telNo; String address; boolean bookHotelForHim; String hotelName; Date checkInDate; Date checkOutDate; boolean isSingleRoom; String idOfSeminarsRegistered[]; Date seminarRegistrationDates[]; boolean needSIDeviceForEachSeminar[]; void setHotelBooking(String hotelName, Date checkInDate, ...) { ... } void registerForSeminar(String seminarId, Date regDate, boolean needSIDevice) { //将seminarId加到idOfSeminarsRegistered //将regDate加到seminarRegistrationDates //将needSIDevice加到needSIDeviceForEachSeminar. } boolean isRegisteredForSeminar(String seminarId) { ... } Date getSeminarRegistrationDate(String seminarId) { ... } boolean needSIDeviceForSeminar(String seminarId) { ... } String [] getAllSeminarsRegistered() { return idOfSeminarsRegistered; } } 代码开始肿胀起来了 请注意,这已经是我们第二次扩充Participant这个类了。每扩充一次,它就包含了更多的代码(实例变量和方法)及更多的功能。本来它只有4个属性。现在已经是12个了!此外,这个类要处理的业务逻辑也极大的增加了。本来它只需要处理参会者的基本信息(姓名,地址等等),现在它还要包含酒店,酒店预订,研讨会和翻译设备等等的逻辑。如果以后新的需求又来了,我们又要扩充Participant这个类,到时候,这个类要复杂庞大成什么样子! 所以我们得修整这个类了! 那怎么修整Participant这个类呢?怎么让它一直保持在第一天那样的简洁度?在回答这两个问题之前,我们先来考虑一下另一个需要优先回答的问题:给你一个类,你怎么认定它需要修整?怎么判断一个类需要修整 要判断一个类是否需要修整,一个比较主观的方法是:当在读一个类的代码时,看看我们会不会觉得这个类“太长了,“太复杂了,或者讲的概念“太多了?如果会这样觉得的话,我们就认定,这个类需要修整。 另外一个比较简单而且客观的方法是:当发现我们已经在第二次或者第三次扩充这个类的时候,我们认定这个类要修整了。这是一个比较懒惰,被动的方法,但却很有效。 现在让我们看一下怎么修整Participant这个类吧。 抽取出有关酒店预订的功能 首先,先来考虑一下怎么抽取出酒店预订的功能。一个可行的方案是: class Participant { String id; String name; String telNo; String address; } class HotelBooking { String participantId; String hotelName; Date checkInDate; Date checkOutDate; boolean isSingleRoom; } class HotelBookings { HotelBooking hotelBookings[] void addBooking(HotelBooking booking) { ... } } class ConferenceSystem { Participant participants[] HotelBookings hotelBookings; } 现在,Participant这个类就一点都不知道酒店预订的存在。当然,我们不一定要用数组来存放酒店预订情况。比如,我们可以用Map: class Participant { String id; String name; String telNo; String address; } class HotelBooking { String participantId; String hotelName; Date checkInDate; Date checkOutDate; boolean isSingleRoom; } class HotelBookings { HashMap mapFromPartIdToHotelBooking; //必须提供参会者id void addBooking(String participantId, HotelBooking booking) { ... } } class ConferenceSystem { Participant participants[]; HotelBookings hotelBookings; } 这样的方案优点是Participant一点都不知道HotelBooking的存在,Participant不依赖于HotelBooking。 还有另一个可行的方案是: class Participant { String id; String name; String telNo; String address; HotelBooking hotelBooking; } class HotelBooking { String hotelName; Date checkInDate; Date checkOutDate; boolean isSingleRoom; } class ConferenceSystem { Participant participants[]; } 注意到,在这种方案里面,Participant这个类还是要知道HotelBooking的存在,也就是说,Participant还是要知道有酒店预订这回事。只是具体酒店预订是怎么做的,这些真正的功能是放在HotelBooking这个里面实现的。因为每个Participant都直接引用了本人的酒店预订情况,所以可以直接找到他的酒店预订情况。而代价就是,Pariticipant还是要知道酒店预订的概念。从类的关系来讲,Pariticipant还要依赖HotelBooking这个类。 当然,除了以上几种情况,还有许多其他的可行方案。 抽取研讨会的相关功能 现在我们来考虑一下怎么抽取出研讨会的功能。一个可行的方案: class Participant { String id; String name; String telNo; String address; } class SeminarRegistration { String participantId; String seminarId; Date registrationDate; boolean needSIDevice; } class SeminarRegistry { SeminarRegistration registrations[] void registerForSeminar(SeminarRegistration registration) { //将registration加到registrations. } boolean isRegisteredForSeminar(String participantId, String seminarId) { ... } Date getSeminarRegistrationDate(String participantId, String seminarId) { ... } boolean needSIDeviceForSeminar(String participantId, String seminarId) { ... } SeminarRegistration[] getAllRegistrations(String participantId) { ... } } class ConferenceSystem { Participant participants[] SeminarRegistry seminarRegistry; } 当然,除了以上的方案以外,还有其他可行的方案,这里就先不讲。改进后的代码 下面就是改进后的代码: class Participant { String id; String name; String telNo; String address; } class HotelBooking { String participantId; String hotelName; Date checkInDate; Date checkOutDate; boolean isSingleRoom; } class HotelBookings { HotelBooking hotelBookings[] void addBooking(HotelBooking booking) { ... } } class SeminarRegistration { String participantId; String seminarId; Date registrationDate; boolean needSIDevice; } class SeminarRegistry { SeminarRegistration registrations[] void registerForSeminar(SeminarRegistration registration) { //将registration加到registrations. } boolean isRegistered (String participantId, String seminarId) { ... } Date getRegistrationDate(String participantId, String seminarId) { ... } boolean needSIDevice(String participantId, String seminarId) { ... } SeminarRegistration[] getAllRegistrations(String participantId) { ... } } class ConferenceSystem { Participant participants[] HotelBookings hotelBookings; SeminarRegistry seminarRegistry; } 引述 单一职责原则(The Single Responsibility Principle)认为:每个类都应该只为一个理由而修改。当一个类包含许多其他的功能时,很明显违反了单一职责原则。要看更多细节的话,可以看:http://www.objectmentor.com/resources/articles/srp. http://c2.com/cgi/wiki?OneResponsibilityRule系列的PDF下载:敏捷开发的必要技巧 Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd
上一条:敏捷开发的必要技巧:慎用继承下一条:Mediator模式
相关文章: