在《重构——改善既有代码的设计》一书中,有一种重构手法叫Encapsulate Collection
(封装集群),为了演示该重构手法,我写了四个类,通过对比重构前后的代码,加深对
这一重构手法的理解。

类Student有一ArrayList属性,如果没有阅读《重构——改善既有代码的设计》一书,
很多人可能会像我一样,如下设计类Student。但是,如果通过Student.getCourses()
获得对ArrayList属性引用后,就可以任意为Student对象添加“课程”,而Student对象
对此一无所知,这不符合面向对象编程的习惯。

package com.readonlylist;

import java.util.ArrayList;

public class Student
{
    private String name;

private ArrayList<String> courses;

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;
    }

public String getName()
    {
        return name;
    }

public void setName(String name)
    {
        this.name = name;
    }    
}

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对象添加一个新课程。就好像,你必须让顾客自己向购物车里放食物,
而不能在顾客毫不知情下,偷偷向其购物车里放食物。

真是万物皆通情理啊:)

--------------------------------------------------------------------------------------

原文地址:http://hi.baidu.com/onejava/blog/item/10388f2b77d340fae6cd4091.html

Collections.unmodifiableList()的使用与场景的更多相关文章

  1. [ 转]Collections.unmodifiableList方法的使用与场景

    在公司接触到Collections.unmodifiableList(List<? extends T> list)) 觉得用法挺特殊的,所以学习了下,简单而言,看名字就知道,将参数中的L ...

  2. 由Collections.unmodifiableList引发的重构

    原文  http://www.cnblogs.com/persist-confident/p/4516741.html 今天阅读源码的时候,无意中看到了Collections.unmodifiable ...

  3. java中unmodifiableList方法的应用场景

    java对象中primitive类型变量可以通过不提供set方法保证不被修改,但对象的List成员在提供get方法后,就可以随意add.remove改变其结构,这不是希望的结果.网上看了下,发现Col ...

  4. Collections.unmodifiableMap,Collections.unmodifiableList,Collections.unmodifiableSet作用及源码解析

    在文章:Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析中mybatis的源码中用到了Collections.unmodifiableList方法,其实还有unmodifiabl ...

  5. [Guava官方文档翻译] 7. Guava的Immutable Collection(不可变集合)工具 (Immutable Collections Explained)

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3538666.html ,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体 ...

  6. Collections、Arrays 简明

    Collections : 它的出现给集合操作提供了更多的功能.这个类不需要创建对象,内部提供的都是静态方法. 一般方法 Collections. sort (list); list 集合进行元素的自 ...

  7. 【Java集合的详细研究1】Collections类常用方法总结

    1.sort(Collection)方法的使用(含义:对集合进行排序). 例:对已知集合c进行排序? public class Practice { public static void main(S ...

  8. Java:集合,Collections工具类用法

    Collections工具类提供了大量针对Collection/Map的操作,总体可分为四类,都为静态(static)方法: 1. 排序操作(主要针对List接口相关) reverse(List li ...

  9. Java中的集合框架-Collections和Arrays

    上一篇<Java中的集合框架-Map>把集合框架中的键值对容器Map中常用的知识记录了一下,本节记录一下集合框架的两个工具类Collections和Arrays 一,Collections ...

随机推荐

  1. jdbc中的Statement对象和Preparedstatement对象的区别,以及通过jdbc操作调用存储过程

    一. java.sql.*   和  javax.sql.*的包的类结构 |- Driver接口: 表示java驱动程序接口.所有的具体的数据库厂商要来实现此接口. |- connect(url, p ...

  2. eclipse慢 优化(转)

    1.打开 eclipse.ini -showsplash com.genuitec.myeclipse.product --launcher.XXMaxPermSize 256M -vmargs -D ...

  3. Tomcat部署多个项目及相关配置

    1.配置多个项目 在tomcat的conf目录下,找到server.xml,在其中添加<Host>节点即可进行多个项目的部署 <Host name="localhost&q ...

  4. 我牵头,你做事——C#委托实践

     我牵头,你做事——C#委托实践一 2007-09-05 23:54:54 标签:委托 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http ...

  5. DCI

    理论: 某个data,在一个特定的场景中,以某个角色role,来与该场景中的其他角色进行交互.这个过程要以代码的方式表达出来,他要求data本身不具备交互行为, 有交互行为的是角色,当一个data没有 ...

  6. 实验一:C语言实现DES加解密算法

    计算程序执行10万次需要的时间: 总共需要175秒 加解密一次的时间小于:0.00175秒 纯计算加解密的时间会更短 去除IO操作后的时间 也就是说加解密一次的时间为0.07毫秒 /*-------- ...

  7. laravel框架——保存用户登陆信息(session)

    public function inlog(Request $request) { //获取表单提交的数据 $input = $request->all(); //根本获取的数据去数据库中查询 ...

  8. API风格

    Client------------ Request ----------------->多Server端 Server------------------------------------- ...

  9. Xamarin.Forms Hello word

    创建项目 XMD1右键->添加->新建项目 MDPage:MasterDetailPage 主窗体,导航与明细的布局窗体. 指定MenuPage.xaml 作为Master <?xm ...

  10. <<开源硬件创客 15个酷应用玩转树莓派>>

    本书共分18章,前3章是本书的基础章节,主要介绍了树莓派的一些基本情况和基本操作,来让读者了解树莓派的前世今生,掌握树莓派基本的使用方法.第4~18章主要介绍15个以树莓派为载体的酷炫应用,大家可以按 ...