【IT168 技术文章】 这是一个会议管理系统,它用来管理所有参会者的信息。刚开始的时候,我们只需要记录每个参会者的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;
}
