面向对象的基本特征:封装,继承,多态。
面向对象设计的基本原则:
1.单一职责原则
一个类只有一种职责或功能,只有一个引起它变化的原因。
这里的单一并不是粒度越小越好,很多时候要根据经验和实际情况进行考虑。
遇到以下情况,我们应该考虑单一职责原则是否满足:
- 类的代码行数过多
- 类依赖的其他类过多
- 过长的方法
- 私有方法过多
- 类名中包含两个或以上名词
例子:
public class User {
int id;
String name;
String address;
String area;
String city;
String province;
}
类中包含一些地址信息,这时,我们可以把这些信息摘出来。
public class Address {
String address;
String area;
String city;
String province;
}
这样User类就变成了:
public class User {
int id;
String name;
Address address;
}
2.开放封闭原则
对扩展开发对修改关闭。基本的意思就是尽量不对原有逻辑进行修改,鼓励通过扩展来实现新增功能,那就要求我们对抽象进行编程,用抽象来搭建框架,因为抽象是相对稳定的。
3.里氏替换原则
所有父类出现的地方,都可以用子类来替换,并且不会出现错误和异常。
四层含义:
1、子类必须实现父类的抽象方法,但不能重写父类的非抽象方法;
如果重写父类的非抽象方法,容易引发意向不到的问题。
2、子类可以定义自己特有的方法;
3、当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松;
4、当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
4.依赖倒置
上层模块不应该依赖于底层模块的具体实现,他们都应该依赖于抽象;
抽象不应该依赖于细节(实现),(实现)细节应该依赖于抽象。
依赖倒置的核心思想是对接口编程。
之前上层模块依赖下层模块的具体实现
上层模块依赖下层模块
现在上层模块和下层模块都依赖于下层模块的抽象,依赖被倒置了。
依赖倒置了
举个例子:小明爱打羽毛球。
class Badminton {
public void play() {
System.out.println("play badminton");
}
}
class XiaoMing {
public void playBadminton(Badminton badminton) {
badminton.play();
}
}
XiaoMing xiaoMing = new XiaoMing();
xiaoMing.playBadminton(new Badminton());
如果小明突然想打篮球了,或玩乒乓球了,该怎么办呢?
我们只能扩展playBadminton方法传入类型或者提供对应的方法,这就违背了开闭原则,耦合性太强。这个时候我们该怎么办呢?
这里XiaoMing就相当于上层模块,Badminton相当于下层模块,我们可以让XiaoMing依赖下层模块的抽象。
interface IBall {
void play();
}
class Basketball implements IBall {
@Override
public void play() {
System.out.println("play basketball");
}
}
class Badminton implements IBall {
@Override
public void play() {
System.out.println("play badminton");
}
}
class XiaoMing {
public void playBall(IBall ball) {
ball.play();
}
}
这样就实现了解耦,小明想进行其他运动时,只有新创建一个实现即可。
5.接口隔离
客户端不应该被迫依赖它不使用的方法或者一个类对另一个类的依赖应该建立在最小的接口上。
也就是说要创建专用的接口,不要试图去创建一个庞大的臃肿的接口供所有类使用。
接口不隔离
类A依赖接口中的方法1和方法2,类B依赖接口中的方法1和方法3.
这样的话类A中就会有冗余的方法3,类B中有冗余的方法2,如果我们要修改方法2,类A和类B都会跟随修改,类A的修改可以理解,但类B的修改属于不必要的修改。
接口隔离
我们把之前的接口拆成3个接口,让他们分别依赖,但接口的拆分也是有限度的,不是越小越好。
6.迪米特法则
迪米特法则又叫最少知道原则,一个对象应该对其他对象保持最少的了解。
目的是降低类与类之间的耦合。
一个简单的定义是:只与直接的朋友通信。成员变量,方法参数和方法返回值中的类为类的直接朋友,出现在局部变量中的类则不是直接的朋友。
比如,咱们举个播放视频的例子。
interface IVideo {
void play();
}
class Video implements IVideo {
@Override
public void play() {
}
}
interface IFetcher {
IVideo fetch(String url);
}
class VideoFetcher implements IFetcher {
@Override
public IVideo fetch(String url) {
return new Video();
}
}
interface IPlayer {
void play(IVideo video);
}
class VideoPlayer {
public void play(String url) {
IFetcher fetcher = new VideoFetcher();
IVideo video = fetcher.fetch(url);
video.play();
}
}
这里我们认为视频播放分为两步,先获取再播放,fetcher和player应该是相互独立的,他俩不是直接的朋友关系,违背了迪米特法则。
interface IPlayer {
void play(IVideo video);
}
class VideoPlayer implements IPlayer {
public void play(IVideo video) {
video.play();
}
}
IFetcher fetcher = new VideoFetcher();
IPlayer player = new VideoPlayer();
player.play(fetcher.fetch(""));
改造之后是这样的,这样就符合迪米特法则了,每个人只和自己的直接朋友打交道。
参考:
1、https://www.cnblogs.com/hunternet/p/14646443.html
2、https://cloud.tencent.com/developer/article/1836753
3、https://www.jianshu.com/p/cf9f3c7c0df5
网友评论