面对对象三大特性

封装、继承、多态

UML图

image-20240104164237808

继承关系

父子继承

image-20240104164319006

实现接口

实现接口

image-20240104164341390

关联关系

image-20240104164400756

聚合关系

弱包含关系,B可以不是A的一部分

image-20240104164417747

组合关系

强包含关系,B是A的一部分

image-20240104164428624

依赖关系

强耦合

image-20240104164504261

六大设计原则

单一职责原则:一个类只负责一个功能

开放-封闭原则:对于拓展开放、对于更改封闭,只对需要频繁修改的那部分抽象(抽象类)

依赖倒转原则:细节依赖抽象(面向接口编程)

里氏代换原则:子类可以替换其父类,这让开放-封闭原则成为可能

迪米特法则:前提是类封装的思想,强调类间的松耦合

创建型模式

隐藏创建类对象的过程,体现高内聚、低耦合

工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式

简单工厂模式

比如要实现一个计算器功能,我们用 switch 或者 if 根据符号来判断用哪个工厂生成答案,如果需要增加复杂的运算,只需要 switch 多加一个选择,多加一个工厂类就可以了

image-20240104171815675

工厂模式

工厂模式是对简单工厂模式的抽象和拓展,每个产品都有相对应的工厂,避免了修改源代码(switch加分支)破坏开放-封闭原则,但是却需要增加产品类和工厂类

image-20240112092605378

抽象工厂模式

每个工厂可以生产不止一种产品,而是同一系列(同一家公司)的很多种产品

抽象工厂模式每次新增一个抽象产品类要修改的代码太多,既要新增产品类,还要修改原有工厂类,这个时候可以采用简单工厂模式 + 抽象工厂模式代替

image-20240118092215680

单例模式

该类只有全局唯一实例化对象

饿汉式:优点是无线程安全问题,类加载就创建对象;缺点是占内存

1
2
3
4
5
6
7
class Singleton01{
private static Singleton01 instance = new Singleton01();//声明对象同时私有化

public static Singleton01 getInstance(){//向外声明访问该类对象的方法
return instance;
}
}

懒汉式:优点是延迟加载,创建后才占用内存;缺点是有线程安全问题,需要双重检查锁保证

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
// 1.线程不安全 
class Singleton02 {
private static volatile Singleton02 instance = null;//声明对象,不实例化

public static Singleton02 getInstance(){//向外提供访问该类对象的方法
if (instance == null){
instance = new Singleton02();
}
return instance;
}
}
// 2.double-check锁保证线程安全
class Singleton02 {
// 由于锁已经保证了可见性,这里volatile的作用是防止new过程中的指令重排
private static volatile Singleton02 instance = null;//声明对象,不实例化

public static Singleton02 getInstance(){//向外提供访问该类对象的方法
if (instance == null){
synchronized(Singleton02.class){
if(instance == null){
instance = new Singleton02();
}
}
}
return instance;
}
}

image-20240119092547006

建造者模式

Director包装了Buider,然后传入不同的ConcreteBuider,可以实现不同细节、但是相同工序的包装

image-20240116094545444

原型模式

原型模式通过拷贝来产生新的对象,而不是new,并且可以根据自己的需求修改对象的属性

image-20240114094925346

结构型模式

隐藏了真正功能对象的行为

适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

适配器模式

image-20240118094746255

装饰器模式

Decorator类包装了Component类,具体的表现为几个ConcreteDecoration类按顺序包装了ConcreteComponent类

image-20240110095518675

代理模式

代理类Proxy通过调用真实对象的方法,代替真实对象RealObject来做事情,并且可以对功能进行拓展

image-20240112091741429

外观模式

提供一个Facade解除客户端和系统的耦合度,调用系统的功能也只需要通过Facade调用即可,完美体现了依赖倒置原则和迪米特法则

image-20240115095208923

桥接模式

把抽象部分分离,就是可以按某个抽象分类,也可以按别的抽象分类,手机品牌、手机软件,然后将他们组合代替继承

image-20240119094414641

组合模式

对于用户来说不用关心访问的是树枝还是树叶,他们在外观表现上没有任何区别,只不过树枝里面还能有树叶罢了

image-20240119091433198

享元模式

共享一些系统资源(CPU、内存),让一些类的对象可以复用(如串池的String),内部实现不变,外部实现可以改变

FlyweighFactory生产Flyweigh,分为要复ConcreteFlyweigh用的和独享的UnsharedConcreteFlyweigh

image-20240121092245279

行为型模式

策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

策略模式

Strategy策略类定义了某个各种算法的公共方法,不同的算法类通过继承Strategy策略类,实现自己的算法

Context的作用是减少客户端和Strategy策略类之间的耦合,客户端只需要调用Context并且传递相应的算法参数,来调用不同的算法,Context的内部实现可以用简单工厂模式

image-20240104171319410

模板方法模式

将一些不变的行为放到父类中,需要变化的行为交给子类实现,其实是对继承、多态的运用

image-20240115093959050

迭代器模式

遍历某个集合的时候,无需关心它的每个元素之间的区别以及其内部结构

image-20240119092344227

观察者模式(发布 - 订阅模式)

观察者根据主题类的状态变化来改变自身状态

image-20240117095129017

责任链模式

让某个请求能够被链上某个处理器处理,也可能不处理

image-20240121090952473

命令模式

利用命令类Invoker解耦了Client和Receiver,也减少了Receiver的职责,符合单一职责,如果说Client的要求是需要能够改动的,那么在Invoker类就可以随之修改

image-20240119095308963

备忘录模式

其实就是用一个类保存了一些需要恢复的信息,某件事情结束以后,利用这个对象恢复原来的状态

image-20240119090842850

状态模式

根据不同的状态来让类表现出不同的行为,这样想修改某个状态的时候只需要修改某个状态子类就可以

image-20240118094238438

访问者模式

一般不用,保证Vistor只有固定的几类,否则会破坏开放-封闭原则

image-20240121093233652

中介者模式

减少ConcreteColleague之间的耦合,任何一个ConcreteColleague发生改变不影响其它,有一个中介着类来解耦合ConcreteColleagues

image-20240121091556646

解释器模式

暂时跳过

image-20240121092814691

杂谈

策略模式和简单工厂模式的区别?

策略模式的这些算法都是在完成一件事,只不过实现不同;简单工厂模式的这些工厂生产的是不同的产品

当然我个人认为,从代码实现的角度看,Context 等价于 Factory,然后工厂模式没有 Strategy 这一层,直接是不同工厂继承父工厂,有点类似吧

简单工厂模式和工厂模式的却区别?

简单工厂模式的拓展只需增加新的对象类,修改switch分支,工厂模式需要额外新增新的工厂类,修改客户端代码

但是工厂模式可以避免破坏开放-封闭原则

总的来说,简单工厂模式减少了工厂类的数量,并且在抽象工厂模式的时候配合使用可以避免工厂类的修改

工厂模式和抽象工厂模式的却区别?

工厂模式一个工厂类生产一种产品

抽象工厂模式一个工厂类生产一系列很多种产品