由Collections.unmodifiableList引发的重构

今天阅读源码的时候,无意中看到了Collections.unmodifiableList的用法,因为以前没有这样做过,所以查询了他的API,是这样写的

public static <T> List<T> unmodifiableList(List<? extends T> list)

参数:list--这是一个不可修改视图是要返回的列表中。

返回值:在方法调用返回指定列表的不可修改视图。

1、用法探讨:

 1 public class CollectionsListDemo {
 2   public static void main(String[] args) {
 3 
 4       List<String> list = new ArrayList<String>();
 5       list.add("aa");
 6      list.add("bb"); 
 7      
 8       System.out.println("初始化前: "+ list);
 9      
10       //实现 unmodifiable
11       List<Character> immutablelist = Collections.unmodifiableList(list);
12      
13       //修改 list
14       immutablelist.add("zz");     
15   }}
16 
17 结果:
18 
19 初始化前:: [aa, bb]
20 
21 Exception in thread "main" java.lang.UnsupportedOperationException

2、继续追踪,到底什么场景遇到呢?重构是怎么写的的?

在《重构——改善既有代码的设计》一书中,有一种重构手法叫Encapsulate Collection  ,(封装集合),
 
定义是:让函数返回这个集合的副本,并在这个类中提供添加/移除集合的副本
 
为了演示该重构手法
 
这本书介绍的是:我们经常用集合,Collection,可能是Array,ArrayList,set,vector保存一组实例,这样的类通常也会提供针对该集合的取值与设值函数
 
但是集合的处理方式和其他种类略有不同,取值函数不应该返回集合本身,因为这会让用户得以修改集合的内容而集合拥有者去一无所知,这样会对用户暴露过多的对象的内部结构信息。如果一个取值函数确实要返回多个值,他应该避免用户直接操作对象内保存的集合,并隐藏对象内与用户无关的的数据结构
 
此外,不应该为这个集合提供一个设置函数,但是应该提供对象内集合本身添加/删除的函数,这样,集合拥有者(对象)就可以控制集合元素的添加与删除
 
如果做到了上边的一点,集合就很好的封装起来,这样就降低了集合拥有者和用户之间的耦合度
 
常用到的做法:
 
(1)加入为集合添加/移除元素的函数
 
(2)将保存的集合的字段初始化一个空的集合
 
3、下面对上边的内容的例子介绍:
 
原来我这样写的:
 1 import java.util.List;
 2 
 3 public class Student
 4 {
 5         private String userName ;
 6        
 7         private List<String> courses ;
 8        
 9 
10         public Student (String userName , List<String> courses)
11        {
12                this.userName = userName;
13                this.courses = courses;
14        }
15 
16         public String getUserName()
17        {
18                return userName ;
19        }
20 
21         public void setUserName(String userName)
22        {
23                this.userName = userName;
24        }
25 
26         public List<String> getCourses()
27        {
28                return courses ;
29        }
30 
31         public void setCourses(List<String> courses)
32        {
33                this.courses = courses;
34        }
35        
36        
37 
38 }

 

重构后,按照上面介绍的原则,这样重构:

 1 import java.util.ArrayList;
 2 import java.util.Collections;
 3 import java.util.List;
 4 
 5 public class Student
 6 {
 7         private String userName ;
 8 
 9         private List<String> courses ;
10 
11         public Student (String userName , List<String> courses)
12        {
13                this.userName = userName;
14                this.courses = courses;
15        }
16 
17         public String getUserName()
18        {
19                return userName ;
20        }
21 
22         public void setUserName(String userName)
23        {
24                this.userName = userName;
25        }
26 
27         public void addCourse(String course)
28        {
29                courses.add(course);
30        }
31 
32         public boolean removeCourse(String course)
33        {
34                return courses .remove(courses );
35 
36        }
37 
38         public List<String> getCourses()
39        {
40                return Collections.unmodifiableList( courses);
41        }
42 
43         public static void main(String[] args)
44        {
45               List<String> list = new ArrayList<String>();
46               list.add( "数学");
47               list.add( "语文");
48               Student s = new Student("lily" , list);
49 
50               List<String> anotherList = s.getCourses();
51 
52                /**
53                * throws java.lang.UnsupportedOperationException should replace with
54                * s.addCourse(String course)
55                */
56               anotherList.add( "英语");
57 
58                // 不会走到这一步,因为上边抛出了异常
59               System. out.println("lily's course.length = " + s.getCourses().size());
60        }
61 
62 }

4、总结

使用这种方法重构的意义:就好比我们网上购物一样,你可以往购物车添加自己想买的东西,但是商户不能在不通知顾客(我们)的情况下,就任意的添加商品,并修改商品的价格等,入口只能是一个,也就是在顾客手中。比喻可能不是很恰当,反正意思大概就是这样。

 

posted @ 2015-05-21 09:51  学会坚持  阅读(8495)  评论(4编辑  收藏  举报