zoukankan      html  css  js  c++  java
  • 回到基础:封装集合

    以前学面向对象时,了解到它有三种特性:

    • 封装
    • 继承
    • 多态

    Java中封装的实现,是通过为私有成员提供访问器方法,即通常所知的getter和setter方法。这样封装是否合适仍属争议,也超出了本文的 讨论范围。但是,当成员变量为集合类型(java.util.Collection,java.util.Map以及它们的子类)时,这样实现封装是完全 错误的。

    我经常能见到的代码像下面这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class MyBean {
        private Collection collection;
     
        public Collection getCollection() {
            return collection;
        }
     
        public void setCollection(Collection collection) {
            this.collection = collection;
        }
    }

    就我所见,这样的代码很普遍,这是由于Hibernate等ORM框架使得这种设计变得流行。很多时候,当我提出我的观点,得到的建议就是使用一种不可变的设计:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class MyBean {
        private Collection collection;
     
        public MyBean(Collection collection) {
            this.collection = collection;
        }
     
        public Collection getCollection() {
            return collection;
        }
    }

    不合适的封装

    然而,在使用集合类型的情形下,由于Java中集合类型自身是可变的,这其实并没有任何改变。很明显,无论是通过构造函数传入一个集合实例的引用, 还是返回它的引用,这完全没有进行封装。只有当集合实例的引用没有(在外部)保留,也不会返回(到外部),真正的封装才有可能实现。

    1
    2
    3
    List list = new ArrayList();
    MyBean mybean = new MyBean(list);
    list.add(new Object()); // 我们在mybean外部改变了封装的集合

    不能使用具体的子类

    另外,MyBean类可能需要封装一种更具体的集合类,比如List或者Set。从下面的代码片段可以看出,传入一个Set实例是不可能的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class MyBean {
        private List collection;
     
        public List getCollection() {
            return collection;
        }
     
        public void setCollection(List collection) {
            this.collection = collection;
        }
    }

    不能选择具体的实现

    由上一点很自然地想到,使用(外部)提供的引用的话,我们也无法使用(可能为了更高效)自己定义的类,比如Apache Commons的FastArrayList。

    实现建议

    下面的代码做到了真正封装的出发点。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class MyBean {
        private List collection = new ArrayList();
     
        public MyBean(Collection collection) {
            this.collection.addAll(collection);
        }
     
        public Collection getCollection() {
            return Collections.unmodifiableList(collection);
        }
    }

    这种方式解决了前面提到的几个问题:

    1. 集合实例的引用没有从构造函数中传入,这样就不可能在实例外部改变实例。
    2. 由于完全隔离,可以自由地选择集合的实现,为修改留下余地。
    3. 不能通过getter访问器方法获得被封装的集合实例的引用。

    注意:为了可读性,前面的代码片段没有使用泛型。请在实际使用中加上。

  • 相关阅读:
    关于石家庄铁道大学课程信息管理系统详细制作过程
    文件与流课后作业
    动手动脑java异常处理
    【HAOI2010】订货
    传纸条
    至省选の計劃
    P1382 光棍组织
    P1834 种花小游戏
    USACO 2015 December Contest, Gold Problem 2. Fruit Feast
    python操作
  • 原文地址:https://www.cnblogs.com/Lightning-Kid/p/3933788.html
Copyright © 2011-2022 走看看