在《重構——改善既有代碼的設計》一書中,有一種重構手法叫Encapsulate Collection
(封裝集羣),爲了演示該重構手法,我寫了四個類,經過對比重構先後的代碼,加深對
這一重構手法的理解。java
類Student有一ArrayList屬性,若是沒有閱讀《重構——改善既有代碼的設計》一書,
不少人可能會像我同樣,以下設計類Student。可是,若是經過Student.getCourses()
得到對ArrayList屬性引用後,就能夠任意爲Student對象添加「課程」,而Student對象
對此一無所知,這不符合面向對象編程的習慣。web
package com.readonlylist;編程
import java.util.ArrayList;this
public class Student
{
private String name;設計
private ArrayList<String> courses;orm
public Student(String name, ArrayList<String> courses)
{
this.name = name;
this.courses = courses;
}
public ArrayList<String> getCourses()
{
return courses;
}對象
public void setCourses(ArrayList<String> courses)
{
this.courses = courses;
}rem
public String getName()
{
return name;
}get
public void setName(String name)
{
this.name = name;
}
}it
package com.readonlylist;
import java.util.ArrayList;
public class Test
{
public static void main(String[] args)
{
ArrayList<String> list = new ArrayList<String>();
list.add("001");
list.add("002");
Student s = new Student("Tom", list);
ArrayList<String> anotherList = s.getCourses();
anotherList.add("999");
System.out.println("Tom's course.length = " + s.getCourses().size());
}
}
重構後的Student類以下所示:
package com.readonlylist;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Student1
{
private String name;
private ArrayList<String> courses;
public Student1(String name, ArrayList<String> courses)
{
this.name = name;
this.courses = courses;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public void addCourse(String course)
{
courses.add(course);
}
public String removeCourse(String course)
{
boolean removed = courses.remove(courses);
if (removed)
{
return course;
}
else
{
return null;
}
}
public List<String> getCourses()
{
return Collections.unmodifiableList(courses);
}
}
package com.readonlylist;
import java.util.List;
import java.util.ArrayList;
public class Test1
{
public static void main(String[] args)
{
ArrayList<String> list = new ArrayList<String>();
list.add("001");
list.add("002");
Student1 s = new Student1("Tom", list);
List<String> anotherList = s.getCourses();
/**
* throws java.lang.UnsupportedOperationException
* should replace with s.addCourse(String course)
*/
anotherList.add("999");
// never reached
System.out.println("Tom's course.length = " + s.getCourses().size());
}
}
重構後,Student1類,僅對外提供的getCourses()方法,而沒有setCourses()方法,並且經過getCourses()方法得到的courses是「只讀的」,若是你試圖向其添加一個新課程,則拋出java.lang.UnsupportedOperationException。你必須經過Student1.addCourse()來向特定的Student1對象添加一個新課程。就好像,你必須讓顧客本身向購物車裏放食物,而不能在顧客絕不知情下,偷偷向其購物車裏放食物。