avatar

目录
java设计模式-UML简述&软件设计七大原则

[TOC]

UML简述

参考:第2章 UML急速入门

概述

Code
1
2
3
4
5
6
7
8
9
10
11
12
UML的定义
UML的特点
UML2.2的分类
结构式图形
行为式图形
交互式图形
UML类图
记忆技巧
UML时序图
1、黑色的实线和实心箭头表示同步调用
2、黑色的实线和空心箭头表示异步调用
3、黑色的虚线和空心箭头就表示方法的返回值

UML类图

UML类图讲解

Code
1
2
3
4
5
6
7
1、如果出抽象类,类名是用斜体来表示
2、"+"表示public
3、"-"表示private
4、"#"表示protected
5、"~"或者什么都不加就表示default的包权限
6、有下划线"_"表示static的属性或者是方法
7、斜体的表示的是抽象方法,既然这个类里面含有抽象方法,那么这个类也必然是一个抽象类

UML类图讲解-自上而下

Code
1
2
3
4
5
6
7
8
《大话设计模式》
依赖关系:一般是作为一个方法的入参:
继承的关系:这里要注意的是:箭头的指向,是从子类指向父类 鸟 is a 动物
组合关系:组合关系的两个类是具有相同的生命周期的; 鸟 翅膀
关联关系:一个类把另一个类作为属性
聚合关系:这里要注意菱形和箭头的方向不要指反了,菱形是多的一方。 大雁 雁群
实现接口:
棒棒糖表示法

UML类图讲解-对比讲解

Code
1
2
3
依赖是虚线、关联是实线
聚合是空菱形、组合是实菱形
继承是实线、实现是虚线

软件设计七大原则

参考:第3章 软件设计七大原则

开闭原则

定义:对扩展开放,对修改关闭

java
1
2
3
4
5
6
7
8
9
10
public interface ICourse
public class JavaCourse implements ICourse

接口应该是稳定的,不应该是经常修改的。

// 打折
public class JavaDiscountCourse extends JavaCourse

我们通过了继承了基类,然后对其进行扩展,对扩展是开发的,而对修改接口和基类是关闭的;
越是基层的模块的修改影响的范围是越大的。

依赖倒置原则

定义:高层[tom]不该依赖底层[JavaCourse]、两者都该依赖其抽象[ICourse]

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
面向实现来进行编程,面向实现类来进行编程的话, 扩展性比较的差,这个就是依赖于底层的实现的

改为面向接口编程:
public class JavaCourse implements ICourse
public class FECourse implements ICourse

public class Tom {
public void studyCourse(ICourse iCourse) {
iCourse.studyCourse();
}
}

注入:
通过接口方法的方式来注入
tom.studyCourse(new JavaCourse());
通过构造器的方式来注入
Tom tom = new Tom(new JavaCourse());
tom.studyCourse();
利用set方法来进行注入
Tom tom = new Tom();
tom.setiCourse(new JavaCourse());
tom.studyCourse();

单一职责原则

定义:不要存在多于一个导致类变更的原因

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Bird

那么现在就是有问题的 ,鸵鸟不是用翅膀飞的。
这个时候,我们在原来Bird类里面进行扩展:这个时候,是不遵循单一职责原则的

这个时候,我们按照职责的不同来进行拆分:

public class FlyBird
public class WalkBird

案例2:
public interface ICourse
这个接口里面含有两个大块的功能:一个是获取课程的相关的信息,一个是对课程进行管理:

这个时候,我们就是可以对上面的接口进行一个拆分:

public interface ICourseContent
public interface ICourseManager

实现类:
public class CourseImpl implements ICourseManager,ICourseContent


要看实际的情况,不能过少的运用单一职责原则,也不能过多的使用单一职责原则,如果类过多的话,会引起来类的爆炸的现象;

接口隔离原则

定义:用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface IAnimalAction {
void eat();
void fly();
void swim();
}

public class Dog implements IAnimalAction
但狗不会飞

我们可以对上面的接口来进行细化
public interface IEatAnimalAction
public interface IFlyAnimalAction
public interface ISwimAnimalAction


我们在设计接口的时候,也不能分的太细,让接口过多;接口隔离原则在使用的时候,一定要适度,用的过多,或者过少都是不好的。

迪米特原则

定义:一个对象应该对其他对象保持最少的了解。又叫【最少知道原则】

java
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
public class Course
// 负责人
public class TeamLeader {
public void checkNumberOfCourses(List<Course> courseList) {
System.out.println("在线课程的数量是:"+courseList.size());
}
}

public class Boss {
public void commandCheckNumber(TeamLeader teamLeader) {
List<Course> courseList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
// new Course()不该出现在Boss类
courseList.add(new Course());
}
teamLeader.checkNumberOfCourses(courseList);
}
}

在Boss这个类的下达指令的方法里面,除开入参 ,出参, 还有类里面的成员变量,这些变量称为朋友,其他的都不能称为朋友,在下达指令的这个方法里面不应该和Course的这个类有任何的交互,这里就是违背了迪米特法则。
【只和朋友交流,不要和陌生人说话】

---------------------------------
修改:

public class TeamLeader {
public void checkNumberOfCourses() {
List<Course> courseList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
// new Course()交给TeamLeader
courseList.add(new Course());
}
System.out.println("在线课程的数量是:"+courseList.size());
}
}

public class Boss {
// 和 Course()没关了
public void commandCheckNumber(TeamLeader teamLeader) {
teamLeader.checkNumberOfCourses();
}
}


在使用迪米特法则的时候,我们要区分哪些是朋友,哪些不是朋友;

里氏替换原则

定义:任何基类可以出现的地方,子类一定可以出现。 LSP(里氏替换原则)是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为

引申:子类可以扩展父类功能,但不能改变父类原有功能

java
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
54
55
56
57
58
59
60
61
62
63
64
开闭原则的时候,在获取打折价格,我们是这样来写的:
public class JavaDiscountCourse extends JavaCourse {
/** 获取原价的方法 */
public Double getOriginPrice() {
return super.getPrice();
}

@Override
public Double getPrice() {
return super.getPrice()*0.8;
}
}

这里的getPrice()方法已经是重写了父类里面的非抽象方法,不符合里氏替换原则
优点:约束继承泛滥

改:

public class JavaDiscountCourse extends JavaCourse {
/** 获取原价的方法 */
public Double getDiscountPrice() {
return super.getPrice()*0.8;
}
}

---------------------------
案例2:

描述一下长方形和正方形的关系
public class Rectangle {
private long length;
private long width;

//get set
}

public class Square extends Rectangle{
private long sidelength;
//get set

@Override
public long getLength() {
return getSidelength();
}

@Override
public void setLength(long length) {
setSidelength(length);
}
}
上面的实现是不符合里氏替换原则的;

改:

四边形的接口:
public interface Quadrangle {
long getWidth();
long getLength();
}

长方形这个类来实现上面的接口
public class Rectangle implements Quadrangle
正方形:
public class Square implements Quadrangle

合成复用原则

定义:尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的

java
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
public class DBConnection {
public String getConnection() {
return "MySQL的数据库连接";
}
}
public class ProductDao extends DBConnection {
public void addProduct() {
String conn = super.getConnection();
System.out.println("使用"+conn+"增加产品");
}
}

现在需要再用Oracle的数据库来进行连接

改:
public abstract class DBConnection {
public abstract String getConnection();
}
public class MySQLConnection extends DBConnection
public class OracleConnection extends DBConnection

// 使用组合而不是继承!!
public class ProductDao {
private DBConnection dbConnection;

// 如参放DBConnection的实现类
public void setDbConnection(DBConnection dbConnection) {
this.dbConnection = dbConnection;
}

public void addProduct() {
String conn = dbConnection.getConnection();
System.out.println("使用"+conn+"增加产品");
}
}

如果我们还有再进行扩展的话,那么我们就再写上一个类 ,然后去实现DBConnection里面的抽象方法,具体的实现由调用者自己去决定new哪一个实现的实例。
文章作者: Machine
文章链接: https://machine4869.gitee.io/2019/03/26/20190326162203290/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 哑舍
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论