教学视频地址:哔哩哔哩尚硅谷java设计模式2019教学视频
一、七大设计原则
1、单一职责原则
一个对象或一个方法只干一件事情减少耦合
注:可以在类的级别遵守单一职责,但有时候也可以在同一个类中的不同方法的级别实现单一职责原则
优点:
2、接口隔离原则
例如:
D、B实现接口1,但A只用到了1、2、3方法,C只用到了1、4、5方法
同一个类实现多个接口用逗号隔开即可:
3、依赖倒转原则
-
基本概念
-
例子:
实现Person接受信息的功能
-
改进:
利用接口回调可直接将具体类放到需要接口参数的位置
- 依赖关系传递的三种方式:
通过接口参数传递
在实现接口时通过构造方法中的参数传递
通过seter方法将参数放进来,实现传递
4、里氏替换原则
- 基本概念
- 例子:
B类无意重写了A类的方法
类似于动物->哺乳动物->老虎,但我们需要修改老虎中的一个方法(如吃东西方式),但这样会影响到父类的方法,因此我们可以把老虎继承动物,然后去引用腐乳动物的方法,其他方法自己新添加,不需要重写
5、开闭原则
- 基本概念
- 例子:
- 优缺点:
增加三角形后需要修改分支判断,而且三角形子类中并没有绘画的的具体实现,所以还要到父类中实现具体的绘画方法,不符合开闭原则
解决方法:
在shap类中新增一个绘制方法,让具体的子类重写这个绘制方法即可,这样也不用在父类使用分支判断了,新增子类也可以直接在新增的子类中写具体的方法。 - 总结
对于需要具体实现的方法,不要放在较为基础的类,应该写成接口,下放到更加具体的类中去实现
6、迪米特原则
-
基本概念
方法内变量可称为局部变量 -
例子:
学校中有学院和总部,现要求学校打印出学院和总部的员工ID
大致的程序为:
成员类{
}
学院管理类{
//返回一个成员List,由于是方法返回值,所以直接朋友
获取所有成员的方法(){}
}
学校管理类{
//学院管理类是方法参数,也是直接朋友
输出所有成员方法(学院管理类){
//此处的成员就是局部变量的陌生类,不符合迪米特原则
List<成员> a = 学院管理类.获取所有成员的方法
输出a
}
}
解决方法:
直接在学院管理类中加一个“输出所有成员”的方法,在学校类中直接调用此方法即可
强调学校不要直接管到学院成员那里去,学院成员就应该让学院来管理 -
总结
较为底层的类不要去实现具体的方法,应该把各个对象的逻辑,在对应对象中封装为方法,对外提供接口/方法即可
7、合成复用原则
- 基本原理
二、UML图
UML有很多种图,这里只介绍其中的重点,UML类图
UML类图—六大关系
1)依赖关系
基本概念
成员变量、方法参数、方法返回值、局部变量都算是用到了对方
2)泛化关系
依赖关系的特例
3)实现关系
4)关联关系
导航性:有方向
多重性:一对一,一对多,多对多等这种关系
5) 聚合关系
6)组合关系
- 成员变量是直接new出来的或和主类级联删除,随着主类共生死,不可分离
三、设计模式
分类
1、单例模式
1)基本概念
2)八种方式
1)饿汉式(静态常量)
- 应用
- 代码:
package 设计模式.单例模式;
import java.util.Stack;
/**
* @author 江涛
* @date 2022/2/10
*/
public class 饿汉式静态常量 {
public static void main(String[] args) {
//测试
//无法new
// SingleTon singleTon = new SingleTon();
//只能通过getinstance来获取实例
SingleTon singleTon1 = SingleTon.getInstance();
SingleTon singleTon2 = SingleTon.getInstance();
//获取的是同一个实例
System.out.println(singleTon1.hashCode());
System.out.println(singleTon2.hashCode());
System.out.println(singleTon1==singleTon2);
}
}
class SingleTon{
//1,构造器私有化,外部不能new
private SingleTon(){
}
//2、本类创建对象实例(私有:不可被调用;静态:自动创建;最终:不可改变)
private final static SingleTon instance = new SingleTon();
//提供公有静态方法,返回实例对象(公有:需要被外部调用;静态:外部使用此方法时尚未获得地址,需要无偿使用)
public static SingleTon getInstance(){
return instance;
}
}
结果:
- 优缺点:
2)饿汉式(静态代码块)
- 应用
- 代码:
package 设计模式.单例模式;
/**
* @author 江涛
* @date 2022/2/10
*/
public class 恶汉模式静态代码块 {
public static void main(String[] args) {
//测试
//无法new
// SingleTon singleTon = new SingleTon();
//只能通过getinstance来获取实例
SingleTon singleTon1 = SingleTon.getInstance();
SingleTon singleTon2 = SingleTon.getInstance();
//获取的是同一个实例
System.out.println(singleTon1.hashCode());
System.out.println(singleTon2.hashCode());
System.out.println(singleTon1==singleTon2);
}
}
class SingleTon1{
//1,构造器私有化,外部不能new
private SingleTon1(){
}
//2、本类创建对象实例(私有:不可被调用;静态:自动创建)
private static SingleTon1 instance;
//恶汉模式静态常量一致,但将instance放在静态代码块中,少了个final的修饰但是因为是私有的变量,外部同样无法修改此变量,
// 但是内部可以修改,但一般不会这么做
static {
instance = new SingleTon1();
}
//提供公有静态方法,返回实例对象(公有:需要被外部调用;静态:外部使用此方法时尚未获得地址,需要无偿使用)
public static SingleTon1 getInstance(){
return instance;
}
}
- 优缺点:
3)懒汉式(线程不安全)
- 应用
- 代码:
package 设计模式.单例模式;
/**
* @author 江涛
* @date 2022/2/10
*/
public class 懒汉式线程不安全 {
public static void main(String[] args) {
//测试
//无法new
// SingleTon singleTon = new SingleTon();
//只能通过getinstance来获取实例
SingleTon2 singleTon1 = SingleTon2.getInstance();
SingleTon2 singleTon2 = SingleTon2.getInstance();
//获取的是同一个实例
System.out.println(singleTon1.hashCode());
System.out.println(singleTon2.hashCode());
System.out.println(singleTon1==singleTon2);
}
}
class SingleTon2{
//1,构造器私有化,外部不能new
private SingleTon2(){
}
//2、本类创建对象实例(私有:不可被调用;静态:自动创建)
private static SingleTon2 instance;
//3、提供公有静态方法,返回实例对象(公有:需要被外部调用;静态:外部使用此方法时尚未获得地址,需要无偿使用)
public static SingleTon2 getInstance(){
//当getinstance被调用时才会创建实例
if (instance == null){
instance = new SingleTon2();
}
return instance;
}
}
- 优缺点:
4)懒汉式(线程安全)
- 应用
- 代码:
相较于懒汉式线程不安全的写法,只是在getinstance加了个synchronized - 优缺点:
5)懒汉式(同步代码块)
- 应用
- 代码如上:
- 优缺点:
6)懒汉式(双重检查)
- 应用
- 代码:
class SingleTon3 {
//实战推荐使用这种方法
//1,构造器私有化,外部不能new
private SingleTon3() {}
//2、本类创建对象实例(私有:不可被调用;静态:自动创建)
//volatile:将修改立即更新到主存,防止指令重排,可以看成轻量型的synchronized
private volatile static SingleTon3 instance;
//3、提供公有静态方法,返回实例对象(公有:需要被外部调用;静态:外部使用此方法时尚未获得地址,需要无偿使用)
//加上synchronized即可实现线程安全
public static SingleTon3 getInstance() {
//当getinstance被调用时才会创建实例
//双重验证
if (instance == null) {
synchronized (SingleTon3.class) {
if (instance == null) {
instance = new SingleTon3();
}
}
}
return instance;
}
}
- 优缺点:
7)静态内部类
- 应用:
- 代码:
class Singleton4{
private Singleton4(){}
//内部类在单例声明时不会装载
private static class singeltonInstance{
private final static Singleton4 instance = new Singleton4();
}
//调用getinstance时才会装载内部类,且内部类的装载时线程安全的
public static Singleton4 getInstance(){
return singeltonInstance.instance;
}
}
- 优缺点:
8)枚举
- 应用
- 代码:
package 设计模式.单例模式;
/**
* @author 江涛
* @date 2022/2/10
*/
public class 枚举 {
public static void main(String[] args) {
Singleton5 singleton1 = Singleton5.instance;
Singleton5 singleton2 = Singleton5.instance;
System.out.println(singleton1.hashCode());
System.out.println(singleton2.hashCode());
System.out.println(singleton1==singleton2);
singleton1.sayHello();
}
}
//推荐使用
enum Singleton5{
instance;
public void sayHello(){
System.out.println("Hello!");
}
}
-
结果:
-
优缺点:
2、工厂模式
1) 简单工厂模式
-
代码:
具体看项目,大概就是在创建具体类时需要修改多个父类,就可以把父类中需要修改的代码用一个工厂来代替,更有利于维护扩展
-
基本概念
2) 工厂方法模式
- 基本概念
- 代码
3) 抽象工厂模式
- 基本概念
- 代码
3、 原型模式
- 引入
- 思路
- 基本概念
- 思路
- 将克隆这件事归属到被克隆的对象中,提高了内聚性
- 浅拷贝
- 深拷贝
4、建造者模式
- 引入
- 传统方式
- 建造者模式
5、适配器模式
- 基本概念
- 类适配器
例子
- 对象适配器
- 接口适配器
6、桥接模式
- 引入
- 传统方法
- 桥接模式
注:代码中将Brand换成了Function
7、 装饰者模式
- 引入
暴力引入,单品加调料种类太多
若将调味品作为饮品的属性则需要在执行功能时判断是否是有该调料以及该调料的数量,而且在添加一个新的调料时又要去修改这些判断条件,同样是比较麻烦 - 基本概念
- 总结
首先是让各个基底去继承饮料(A)
其次是将调味料也当成一个饮料类,让描述者(B)去继承饮料,然后再让各个调味料继承描述者
最后再将结合了基底的饮料A聚合进结合了各种调味料的饮料B,然后再描述者中整合两个饮料的各个属性即可
其中再添加调味料时需要一个结合了基底的饮料,如果还需要继续添加调味料,就可以嵌套添加了
8、 组合模式
- 引入
- 基本概念
- 总结
用一个Component抽象类规定一些公共的方法,让所有的叶子节点,中间结点来继承Component
再让各个节点根据层级的关系组合即可
9、外观模式
- 引入
- 外观类基本概念
- 总结
就是封装了一些高级方法
10、享元模式
- 引入
- 基本概念
- 内部状态和外部状态:状态能否共享
- 代码
- 总结
就是在创建对象时先在池子中找,有就返回,没有就加入后再返回,与java的String对象的创建一样
11、代理模式
- 基本概念
- 静态代理
用接口约束代理对象和被代理对象,代理对象通过聚合的方式使用被代理对象即可,即多封装了一层
- 动态代理
- CClib代理
代理的类不能被final修饰
代码(需要导包)
TeacherDAO:
ProxyFactory:
Client:
- 变体(应用)
12、 模板模式
- 引入
将模板方法放在make()方法中 - 钩子方法
13、命令模式
- 引入
- 原理
- 代码
14、 访问者模式
- 引入
- 基本概念
![在这里插入图片描述](https://img-blog.csdnimg.cn/046feb6882204ed69aec968dc1f66bdf.png?x-oss-process=image/watermark,type_d3F5LXplb mhlaQ,shadow_50,text_Q1NETiBAd2VpeGluXzQ3NTg1NDA0,size_20,color_FFFFFF,t_70,g_se,x_16)
- 代码
15、 迭代器模式
- 引入
- 基本概念
- 代码
- 优缺点
16、观察者模式
- 引入
- 基本概念
- 代码
- 优点
17、中介者模式
- 引入
- 基本概念
- 代码
17、备忘录模式
- 引入
- 基本概念
- 代码
19、 解释器模式
- 引入
- 基本概念
- 代码
20、 状态模式
- 引入
- 基本概念
- 代码
21、 策略模式
- 引入
需要覆盖方法,非常麻烦
- 基本概念
- 代码
22、职责链模式
- 引入
- 基本概念
- 代码