面向对象设计OOD

  • 单一职责原则
  • 开放–封闭原则
  • 里氏代换原则
  • 依赖倒置原则
  • 接口隔离原则
  • 迪米特法则

单一职责原则(SPR)

定义:一个类,只有一个引起它变化的原因。

好处:

  1. 可降低类的复杂度。
  2. 复杂度降低,可读性提高。
  3. 可维护性高、风险低,一个接口修改只对相应的实现类有影响,对其他接口没有影响。

原本的代码是这样的 (演示打印用户信息)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Main函数
package study;

public class Main {
public static void main(String[] args) {
System.out.println("this is main");
new CustomerCharts().disPlayCustomer();
}
}

CustomerCharts类
package study;

import java.util.ArrayList;
import java.util.List;

public class CustomerCharts {
protected List<Customer> findCustomers(){
//模拟查找数据库 如果以后换了数据库这几行代码就不成立了, 而CustomerCharts这个类只需要展示数据,对数据从哪儿来的并不关心,所以需要单独把这个提出来重新写。
List<Customer> ret = new ArrayList<>();
ret.add(new Customer("小红", 18));
ret.add(new Customer("小明", 22));
return ret;
}

public void disPlayCustomer(){
for (Customer customer : findCustomers()){
System.out.println("Customer---" + customer.name);
}
}
}

Customer类
package study;

public class Customer {
public String name;
public int age;
public Customer(String name, int age){
this.name = name;
this.age = age;
}

}

修改之后的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package study.single;

public class Main {
public static void main(String[] args) {
System.out.println("this is main");
//new CustomerCharts().disPlayCustomer();
CustomerCharts customerCharts = new CustomerCharts();
customerCharts.setDao(new CustomerDao());
customerCharts.disPlayCustomer();
}
}

package study.single;

public class Customer {
public String name;
public int age;
public Customer(String name, int age){
this.name = name;
this.age = age;
}

}

package study.single;
//这里就实现了单一职责原则,只管显示这一个功能,不需要知道数据从哪儿获取的。
public class CustomerCharts {
CustomerDao dao;

public void setDao(CustomerDao dao) {
this.dao = dao;
}

public void disPlayCustomer(){
for (Customer customer : dao.findCustomers()){
System.out.println("Customer---" + customer.name);
}
}
}

package study.single;

import java.util.ArrayList;
import java.util.List;

public class CustomerDao {
protected List<Customer> findCustomers(){
List<Customer> ret = new ArrayList<>();
ret.add(new Customer("小红", 18));
ret.add(new Customer("小明", 22));
return ret;
}
}

开放—封闭原则(OCP)

定义:软件实体应尽量在不修改原有代码的情况下进行拓展。

高内聚,低耦合。抽象化是开闭原则的关键

优点:降低了各程序之间的耦合性适应性、灵活性、稳定性都比较好。

模拟图表的展示场景 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package study.OCP;

public class Main {
public static void main(String[] args) {
System.out.println("Main test");
ChartDisplayManger chartDisplayManger = new ChartDisplayManger();
chartDisplayManger.display("Bar");
chartDisplayManger.display("Line");
}
}

package study.OCP;

public class LineChart {
public void display(){
System.out.println("LineChart display");
}

}

package study.OCP;

public class BarChart {
public void display(){
System.out.println("BarChart display");
}
}

package study.OCP;

public class ChartDisplayManger {
public void display(String name){
switch (name){
case "Line":
new LineChart().display();
break;
case "Bar":
new BarChart().display();
break;
default:
break;
}
}

}

在想要添加新图表展示的时候,需要增加一个新的图表的类,同时在ChartDisplayManger图表展示管理的类里还需要增加一个判断,这样的话就违反了开放–封闭原则。

修改之后的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package study.OCP;

public class Main {
public static void main(String[] args) {
System.out.println("Main test");
ChartDisplayManger chartDisplayManger = new ChartDisplayManger();
chartDisplayManger.display(new LineChart());
chartDisplayManger.display(new BarChart());
}
}

package study.OCP;

public abstract class BaseChart {
public abstract void display();
}

package study.OCP;

public class LineChart extends BaseChart{
public void display(){
System.out.println("LineChart display");
}

}

package study.OCP;

public class BarChart extends BaseChart{
public void display(){
System.out.println("BarChart display");
}
}


package study.OCP;

public class ChartDisplayManger {
public void display(BaseChart chart){
chart.display();
}

}

这样再增加一个新的图表展示的时候,就只需要添加展示新图表的类。

里氏代换原则(LSP)

定义:一个软件实体如果使用的是一个基类,那么当把这个基类替换成继承该基类的子类,程序的行为不会发生任何变化。

低耦合

优点:可以很容易的实现同一父类下各个子类的互换,而客户端可以毫不察觉。

依赖倒置原则(DIP)

定义:要依赖于抽象,不要依赖于具体。

低耦合

优点:提高代码的可读性和可维护性,减少类与类之间的耦合,提高系统的稳定性。

用一个母亲讲故事的例子来说明 开始的代码是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package study.DIP;

public class Main {
public static void main(String[] args) {
System.out.println("Main test DIP");
Mother mother = new Mother();
mother.readBook(new Book());
}
}


package study.DIP;

public class Mother {
public void readBook(Book book){
System.out.println("Mom is Reading");
book.getBookName();
}

}


package study.DIP;

public class Book {
public void getBookName(){
System.out.println("三毛流浪记");
}

}

在上面代码的基础上再加一个看报纸的类,那么 mother.readBook(new readPaper());这样就违反了依赖倒置原则。

修改之后的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package study.DIP;

public class Main {
public static void main(String[] args) {
System.out.println("Main test DIP");
Mother mother = new Mother();
mother.readBook(new NewPaper());
mother.readBook(new Book());
}
}

package study.DIP;

public class Mother {
public void readBook(IReader iReader){
System.out.println("Mom is Reading");
iReader.getBookName();
}

}


package study.DIP;

public class Book implements IReader{
@Override
public void getBookName(){
System.out.println("三毛流浪记");
}

}

package study.DIP;

public class NewPaper implements IReader{
@Override
public void getBookName() {
System.out.println("青春读物");
}
}

package study.DIP;

public interface IReader {
void getBookName();
}

接口隔离原则(ISP)

定义:使用多个专一功能的接口比使用一个的总接口要好得多。

高内聚

优点:会使一个软件系统功能扩展时,修改的压力不会传到别的对象哪里。

迪米特法则(LKP)

定义:对象与对象之间应该尽可能少的方法来关联。

低耦合