封装

封装十分有用,可以将一些数据信息封装起来,或者隐藏,或者做一些额外的限制操作,而这部分的行为都在内部来进行,对外只保留了适当的接口来提供调用,而类内部的各种信息可以自动修改达到很轻松可控的效果

有一个简单的Girl类

class Girl {
    public String name;
    public int age;
    public int id;
}

类有三个成员变量,分别是姓名,年龄和工号

对于每个新来的员工,都会这样来使用(Girl obj).id来进行操作工号,类型都是int

        Girl girl = new Girl();
        girl.id = 6666;

如果有一天,公司大幅度扩张,疯狂招人,int工号都不够用了(太疯狂!),担心long有一天也会不够用,直接修改成员变量的类型为String,如此一来就变成这样了

class Girl {
    public String name;
    public int age;
    public String id;
}

这下就尴尬了,其它在调用(Girl obj).id的地方,都会因为数据类型的修改,无法编译通过;还需要一个一个修改或者做转换,多加思索就觉得设计方式就有所欠妥,因为Girl类对于我的使用可扩展性太差,看看封装的效果

一开始的Girl类设计成如下

class Girl {
    private String name;
    private int age;
    private int id;

    public String getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

可以看到这种设计方法,将成员变量置为private的,提供public的get和set方法来控制获取和存储操作,此时要用id信息的地方,在这种情形下,存和取的方式如下

        Girl girl = new Girl();
        girl.setId(6666);
        System.out.println(girl.getId());

通过这种方式,能够很安全的对数据进行存和取,或者暂时看不出来封装的优势,再回到上面的问题,假如int工号不够用,要将成员变量修改成String类型,而此时实例调用中setId里面依旧都是int类型,想要兼容现有所有人的用法,很自然的想法就是在setId方法里将传入的int类型做一下类型转换,让getId方法返回String类型,就达到目的了,整个如下

class Girl {
    private String name;
    private int age;
    private String id;

    public String getId() {
        return id;
    }

    public void setId(int id) {
        this.id = String.valueOf(id);
    }
}

public class Main {
    public static void main(String[] args) {
        Girl girl = new Girl();
        girl.setId(6666);
        System.out.println(girl.getId());
    }
}

仔细酝酿一下就会发现所有通过setId存和getId取的地方,就算传入的是int类型,都不需要做任何修改(如果有其它int类型加减等运算应当自行处理),但就这个例子而言,还有一个问题,都已经说过了,此处的int工号已经无法满足了,虽然转换成了String类型,但setId方法传入的还是int类型,因此新来的员工还是无法适配这里,为了眼前兼容,改成long即可

class Girl {
    private String name;
    private int age;
    private String id;

    public String getId() {
        return id;
    }

    public void setId(long id) {
        this.id = String.valueOf(id);
    }
}

public class Main {
    public static void main(String[] args) {
        Girl girl = new Girl();
        girl.setId(2222222222L);
        System.out.println(girl.getId());
    }
}

通过这个例子,就很通俗易懂地发现封装的一些好处,可以自定义地添加一些限制条件,再比如像有些公司,不招聘40岁以上的员工

class Girl {
    private String name;
    private int age;
    private String id;

    public String getId() {
        return id;
    }

    public void setId(long id) {
        this.id = String.valueOf(id);
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 40) {
            System.out.println("NO NEED");
        } else {
            this.age = age;
        }
    }
}

假如说妹纸的年龄在30到40岁之间是保密的

class Girl {
    private String name;
    private int age;
    private String id;

    public String getId() {
        return id;
    }

    public void setId(long id) {
        this.id = String.valueOf(id);
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 40) {
            System.out.println("NO NEED");
        } else if (age > 30) {
            System.out.println("Secret");
        } else {
            this.age = age;
        }
    }
}

其实,还遗漏了一个比较重要的常识限制,年龄假如有人输入一个非常大的数字,显然就相当于有误的,因此可以做一下判断

class Girl {
    private String name;
    private int age;
    private String id;

    public String getId() {
        return id;
    }

    public void setId(long id) {
        this.id = String.valueOf(id);
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 200) {
            System.out.println("Impossible");
        } else if (age > 40) {
            System.out.println("NO NEED");
        } else if (age > 30) {
            System.out.println("Secret");
        } else {
            this.age = age;
        }
    }
}

从这些例子可以看出,类里可以自行进行把控,而这些细节对于实例调用的时候是不需要可见的

通过setter能够做一切可以进行的检查操作,还可以跑出Exception异常,始终记着将类成员变量设置为私有,然后提供公有的getter和setter来进行存取操作,可以保证安全性

发表回复