面向对象设计的三大特性:
- 封装:把客观的事物抽象成一个类,类中定义的属性和方法可以通过public、private、protected来控制他们的访问权限,从而简化编程以及控制访问,例如:
abstract class Person{
private String name;
private String sex;
public String getName(){
return name;
}
public void setName(String newName){
this.name = newName;
}
public String getSex(){
return sex;
}
public void setSex(String newSex){
this.sex = newSex;
}
abstract void show();
}
- 继承:指的是一个类可以拥有另一个类的属性和方法,父类和子类就是继承关系,它的目的就是将一些公共的属性和方法放到父类从而实现代码复用,例如:
class Man extends Person{
Man(){
setSext("男")
}
.. ..
}
class WoMan extends Person{
Man(){
setSex("女")
}
.. ..
}
- 多态:指的是同一个方法可以有不同的实现,它可以屏蔽不同子类的差异,写出通用的代码,以适用需求的变化,例如:
class Man extends Person{
.. ..
void show(){
System.out.println("穿着衬衫、短裤")
}
}
class WoMan extends Person{
.. ..
void show(){
System.out.println("穿着连衣裙")
}
}
面向对象设计原则:
- 单一职责:一个类的应该只做一件事,就是一个类的功能不能太多太杂
- 开闭原则:对扩展开放,对修改关闭,就是说增加新功能尽量不要修改到原来的代码,而是通过继承、接口、抽象等方式扩展功能
- 里氏代换:在出现父类的地方,子类可以替代父类使用,主要说的是继承关系,这里要分两种情况来讨论:如果继承是为了抽出公共方法,那么子类不可以重写父类方法,不然就违反了里氏代换原则;如果继承是为了多态,父类应该定义成抽象类,这样父类就不能实例化,也就不存在违反里氏代换原则
- 依赖倒置:依赖抽象,而不依赖具体实现,意思是说当需要用到某个类的时候,我们应该去引用这个类的抽象类或者接口,这样当这个类发生变化时,能尽可能的不修改到这里的代码
- 接口隔离:定义接口时,职责要单一,定义的方法应该尽可能的少,当需要实现多个功能时,应尽可能去实现多个接口,而不是都写在一个接口里,如果都写在一个接口里,其他只需要用到部分方法的类,都得实现那些不必要的方法,不利于扩展,也违反了前面的单一职责
- 迪米特法则:一个类应该尽可能的少暴露属性和方法,只和直接的对象打交道,不同对象之间尽可能的少了解内部细节;例如一个类的属性,我们一般设为private,而通过public的get\set方法来访问,看下面的代码就是迪米特法则的体现,也就是我们不应该在外部获取到status和data然后判断,因为如果有很多地方都需要做同样的判断,那就很多重复代码了,下面这种写法代码就只要调用Result对象的isResultOk()就可以了,既没有暴露内部属性,也隐藏了内部判断逻辑
class Result{
private String status;
private String data;
private boolean isStatusOk(){
return "1".equals(status);
}
public boolean isResultOk(){
return isStatusOk() && !TextUtils.isEmpty(data);
}
}
- 组合、聚合复用原则:尽量使用组合和聚合,而不是继承来达到目的;就是说我们要尽可能通过组合、聚合方式来复用已有的功能,继承虽然也可以复用已有功能,但是不够灵活,一旦父类发生改变,所有的子类都要跟着变化;
例如,已有一个人的类,现在需要赋予他一种职业,可以是学生、工人、老板,如果采用继承的方式,类结构图就是下面这样的:
但是如果现在要求人可以有多种身份,上面采用继承的方式就无法实现,如果采用组合、聚合的方式就能很好的应对这个需求的变化: