什么是封装?
封装的单词是-encapsulation,意思是把抽象出来的数据和对数据的操作抽象出来,数据被绑定在一起,然后通过几个接口将实现的方法暴露出来。比如电视机的开关机,我们按一下开机的按钮,电视机就被打开了,我们不去关心电视机内部的运行的原理,我们只看到电视机被成功打开了,这就是一种封装思想的运用。
封装解决了什么?
封装使得我们的程序“高内聚,低耦合”
封装的关键词
总共有四个:
- public 公有属性,谁都可以访问它
- private 私有属性,只有本类可以访问它
- 什么也不写,包级protected 只在本包内可以访问它,不包括子类
- protected 本包和其子类可见,注意Java的包是不包括包所包含的包的,Java会认为这个是另一个新的包
Java的封装的实现以及JavaBean
JavaBean约定,在Java中,约定俗成了一些封装的方法的写法,我们定义了Java本身应该包括的几个约定的命名规则如下:
定义getter和setter
应当给出对应的构造器
xxxListener ...
于是在Java中,封装一个类对应的具体代码应该如下:
public Cat{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat(){}
//这段叫做构造方法的重载,我总是记不住,我现在只记单词,Overload
public Cat(String name) {
this.name = name;
}
}
小技巧:不像js中的各种代码的混乱,在Java中由于有各种修饰符,我们就有了修改导入的包的方法,我们可以翻阅源码,对导入的包的名字进行复制,然后在自己的项目中新建这个包,这样就能在原先包的基础上进行修改和暴露方法了,注意这种方法只对包级protected以上的权限管用,private限制还是在自己本包内,我们只能通过继承等方法去解决
静态工厂方法(构造器私有化的封装)
上述的构造方法其实并不完善,有时候,我们只是单纯需要全局一个对象,不想要每个其他类中去new,另外,类名的多端化也是的生成类的时候不知道该生成哪一类,如上的Cat类,我可以传参,也可以不传参,我要new的时候需要翻阅源码,十分的不方便。此时我们可以将构造方法也隐藏起来,在用一层静态的封装去暴露对应的对象,比如Java中的Boolean中返回ture和false对象就是这么写的
工厂模式:在创建对象时不会对客户端暴露创建逻辑,而是通过一个共同的接口来指向新建的对象
static:static的本质是为了方便在内存中不通过对象的方法直接使用类的内部的方法,也就是类似JS中的方法调用的方式,此时Java会在内存中方法区记录每一个static创建的方法,在静态工厂方法中,由于我们调用了static,于是只在第一次方法运行的时候new了一个对象,之后都用的方法区内生成的对象
于是改造我们的上述代码,做成对应的静态工厂方法
...
private Cat() {
}
private Cat(String name) {
this.name = name;
}
public static Cat createEmptyCat() {
return new Cat();
}
public static Cat createCat(String name) {
return new Cat(name);
}
在Effect Java中,他建议我们要多使用静态工厂方法来代替new这种方法产生的对象。
builder模式
在之前的静态工厂方法中,我们解决了实际运用中的new的个数的问题,现在还有问题在于,我们写的方法参数会随着类的增加而增加,参数过多了。 于是我们使用了Builder模式来应对参数过多的情况。代码如下
原生的类
public class Cat {
private final String name;
private final int age;
private final String sex;
public void say(){
System.out.println(this.name + this.age +this.sex);
}
private Cat(String name,int age,String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public static Cat createCat(String name,int age,String sex) {
return new Cat(name,age,sex);
}
}
public final class CatBuilder {
private String name;
private int age;
private String sex;
public static CatBuilder aCat() {
return new CatBuilder();
}
public CatBuilder withName(String name) {
this.name = name;
return this;
}
public CatBuilder withAge(int age) {
this.age = age;
return this;
}
public CatBuilder withSex(String sex) {
this.sex = sex;
return this;
}
public Cat build() {
return Cat.createCat(name,age,sex);
}
}
//比如此时,我们生成了一个cat的实例对象,它只传了参数name
Cat cat = CatBuilder.aCat().withName("大毛").build();
此时我们生成的了一个关于Cat的builder类,可以使用链式调用,对类中的参数我们可以调用,也可以不写全调用,解决了之前因为参数过多而产生的烦恼。