在《重构——改善既有代码的设计》一书中,有一种重构手法叫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

最新文章

  1. Javascript进阶之路-论对象的重要性
  2. Java 对象 及 对象的应用
  3. Recover lost Confluence password
  4. [翻译]Primer on Cognitive Computing(认知计算入门)
  5. oracle合并版本
  6. maven -- 学习笔记(三)之搭建nexus私服
  7. POJ 2352
  8. 修改input的type属性
  9. excel在一个图表内,显示折线图和柱状图
  10. keychain 多应用共享数据
  11. 【转】Xcode 7 真机调试详细步骤
  12. sql查询语句心得
  13. Ghost Button制作教程及设计趋势分析
  14. 【原创】python实现清理本地缓存垃圾
  15. 385cc412a70eb9c6578a82ac58fce14c 教大家破解md5验证值
  16. Request.getparameternames 获取form表单里面所有的请求参数 。 返回一个Enumeration类型的枚举.
  17. Linux 基本bash命令
  18. SpringBoot+BootStrap多文件上传到本地
  19. windows下telnet不是内部或外部命令
  20. Spring学习日志之纯Java配置的MVC框架搭建

热门文章

  1. wpf 控件复制 克隆
  2. WebService笔记-Schema约束
  3. 简单的js反选,全选,全不选
  4. 一个小玩具:NDK编译FFmpeg的例子
  5. 用BroadcastReceiver监听网络状态的变化
  6. 用批处理来重启IIS的应用程序池
  7. 纯js实现分页
  8. 手写 title 提示
  9. 【行为型】TemplateMethod模式
  10. PHP图的绘制1