参考文档:
1,设计模式分类
1,创建型模式
提供了一种在创建对象的同时,隐藏创建逻辑的方式。而不是使用new运算符直接实例化对象。
- 工厂模式
- 抽象工厂模式
- 单例模式
- 建造者模式
- 原型模式
对象池模式多例模式静态工厂模式
2,结构型模式
关注类和对象的组合.
- 适配器模式
- 桥接模式
过滤器模式- 组合模式
- 装饰器模式
- 外观模式
- 享元模式
- 代理模式
数据映射模式依赖注入模式门面模式流接口模式注册模式
3,行为型模式
关注对象间的通信
- 责任链模式
- 命令模式
- 解释器模式
- 迭代器模式
- 中介者模式
- 备忘录模式
- 观察者模式(面试常考)
- 发布-订阅模式(面试常考)
- 状态模式
空对象模式- 策略模式
- 模板模式
- 访问者模式
规格模式访问者模式
2,详解
参看文档:
1,创建型模式
封装对象的创建过程,将对象的创建和使用解耦。
1,单例模式
处理资源访问冲突,用来创建全局唯一对象。
//1,懒汉式:用到的时候才创建
//2,饿汉式:系统启动式创建。
2,工厂模式
用来创建继承同一父类,实现同一接口的子类对象,由给定的类型参数来创建具体的对象。
enum HelloType {
A,
B
}
interface Hello {
sayHello()
}
class A implements Hello {
sayHello() {
console.log('A');
}
}
class B implements Hello {
sayHello() {
console.log('B');
}
}
class HelloFactory {
static list = new Map<HelloType, Hello>([
[HelloType.A, new A()],
[HelloType.B, new B()]
])
static getHello(type: HelloType) {
return HelloFactory.list.get(type)
}
}
// test
HelloFactory.getHello(HelloType.A).sayHello()
HelloFactory.getHello(HelloType.B).sayHello()
3,抽象工厂模式
继承同一父类,实现同一接口的子类对象,由给定的多个类型参数创建具体的对象。
enum Type {
A,
B
}
enum Occupation {
TEACHER,
STUDENT
}
interface Hello {
sayHello()
}
interface Hello2{
getHello(occupation: Occupation)
}
class TA implements Hello {
sayHello() {
console.log('Teacher A say hello')
}
}
class TB implements Hello {
sayHello() {
console.log('Teacher B say hello')
}
}
class SA implements Hello {
sayHello() {
console.log('Student A say hello')
}
}
class SB implements Hello {
sayHello() {
console.log('Student B say hello')
}
}
class AFactory implements Hello2 {
static list = new Map<Occupation, Hello>([
[Occupation.TEACHER, new TA()],
[Occupation.STUDENT, new SA()]
])
getHello(occupation: Occupation) {
return AFactory.list.get(occupation)
}
}
class BFactory {
static list = new Map<Occupation, Hello>([
[Occupation.TEACHER, new TB()],
[Occupation.STUDENT, new SB()]
])
static getHello(occupation: Occupation) {
return BFactory.list.get(occupation)
}
}
class HelloFactory {
static list = new Map<Type, AFactory | BFactory>([
[Type.A, AFactory],
[Type.B, BFactory]
])
static getType(type: Type) {
return HelloFactory.list.get(type)
}
}
// test
HelloFactory.getType(Type.A).getHello(Occupation.TEACHER).sayHello()
HelloFactory.getType(Type.A).getHello(Occupation.STUDENT).sayHello()
HelloFactory.getType(Type.B).getHello(Occupation.TEACHER).sayHello()
HelloFactory.getType(Type.B).getHello(Occupation.STUDENT).sayHello()
4,建造者模式
创建时有很多必填参数需要验证。
创建时参数求值有先后顺序,相互依赖。
创建有很多步骤,全部成功才能创建对象。
class Programmer {
age: number
username: string
color: string
area: string
constructor(p) {
this.age = p.age
this.username = p.username
this.color = p.color
this.area = p.area
}
toString() {
console.log(this)
}
}
class Builder {
age: number
username: string
color: string
area: string
build() {
if (this.age && this.username && this.color && this.area) {
return new Programmer(this)
} else {
throw new Error('缺少信息')
}
}
setAge(age: number) {
if (age > 18 && age < 36) {
this.age = age
return this
} else {
throw new Error('年龄不合适')
}
}
setUsername(username: string) {
if (username !== '小明') {
this.username = username
return this
} else {
throw new Error('小明不合适')
}
}
setColor(color: string) {
if (color !== 'yellow') {
this.color = color
return this
} else {
throw new Error('yellow不合适')
}
}
setArea(area: string) {
this.area = area
return this
}
}
// test
const p = new Builder()
.setAge(20)
.setUsername('小红')
.setColor('red')
.setArea('hz')
.build()
.toString()
5,原型模式
- 1,原型模式是基于已有的对象克隆数据,而不是修改原型链。
- 2,创建对象的代价太大,而同类的不同实例对象属性值基本一致,通过原型克隆的方式节约资源。
- 3,不可变对象通过浅克隆实现。
- 4,可变对象通过深克隆实现,深克隆占用资源多。
- 5,
2,结构型设计模式
总结了一些类或者对象组合在一起的经典结构,这些经典结构可以解决特定应用场景的问题,将类或者对象的结构和使用解耦。
1,桥接模式
- 1,将抽象和实现解耦,让他们可以独立变化。
- 2,一个类存在多个独立变化的维度,通过组合的方式让多个维度可以独立的进行拓展。
- 3,类似于组合优于继承原则。
enum MsgLevel {
ERROR,
WARN,
}
enum MsgType {
EMAIL,
PHONE
}
interface MsgContent {
content()
}
class ErrorMsg implements MsgContent {
content() {
return 'ERROR'
}
}
class WarnMsg implements MsgContent {
content() {
return 'WARN'
}
}
interface MsgSender {
send()
}
class PhoneSend implements MsgSender {
msgContent: MsgContent
constructor(msgContent: MsgContent) {
this.msgContent = msgContent
}
send() {
console.log(`phone send ${this.msgContent.content()}`)
}
}
class EmailSend implements MsgSender {
msgContent: MsgContent
constructor(msgContent: MsgContent) {
this.msgContent = msgContent
}
send() {
console.log(`email send ${this.msgContent.content()}`)
}
}
// test 此处还可以做成map结构继续优化(略)
new PhoneSend(new WarnMsg()).send()
new PhoneSend(new ErrorMsg()).send()
new EmailSend(new WarnMsg()).send()
new EmailSend(new ErrorMsg()).send()
2,代理模式
- 1,给原类添加非功能性需求,为了将代码与原业务解耦。
- 2,业务系统的非功能性需求:监控、统计、鉴权、限流、日志、缓存。
1,通过继承实现
class User {
login() {
console.log('user login...')
}
}
class UserProxy extends User {
login() {
console.log('login before')
super.login()
console.log('login after')
}
}
2,通过接口实现
interface Login {
login()
}
class User implements Login {
login() {
console.log('user login...')
}
}
class UserProxy implements Login {
user = new User()
login() {
console.log('login before')
this.user.login()
console.log('login after')
}
}
3,装饰器模式
- 1,装饰器是对原始功能的增强。
- 2,装饰器类和原始类继承同样的父类,可以对原始类嵌套多个装饰器类
- 3,主要解决继承关系过于复杂的问题,通过组合来替代继承。
- 4,
1,通过AOP实现
Function.prototype.before = function (beforeFn) {
return (...arg) => {
beforeFn(...arg);
return this(...arg);
}
};
Function.prototype.after = function (afterFn) {
return (...arg) => {
const result = this(...arg);
afterFn(...arg);
return result;
}
};
function ImportEvent1() {
console.log('重要的事情说三遍 1')
}
function ImportEvent2() {
console.log('重要的事情说三遍 2')
}
function ImportEvent3() {
console.log('重要的事情说三遍 3')
}
// test
let result = ImportEvent2.before(ImportEvent3).after(ImportEvent1)();
console.log(result);
2,
4,适配器模式
- 1,适配器模式用于不就设计上的缺陷,将不兼容的接口变得兼容。
- 2,适配不同格式的数据。
解决方案
- 1,原接口方法不多,类适配器和对象适配器都可以。
- 2,原接口方法很多,并且和目标接口差异小,使用类适配器减少代码量。
- 3,原接口方法很多,并且和目标接口差异大,用对象适配器,组合由于继承。
// 目标接口格式
interface ITarget {
f1()
f2()
f3()
}
// 原有类与目标接口不兼容
class Origin {
fa() {
}
fb() {
}
f3() {
}
}
// 使用适配器来兼容
class Adaptor implements ITarget {
origin = new Origin()
f1() {
this.origin.fa()
}
f2() {
this.origin.fb()
}
f3() {
this.origin.f3()
}
}
5,享元模式
1,应用场景
共享的单元。复用对象,节省内存,前提是享元对象是不可变对象(初始化之后不可改变)。
6,组合模式
1,应用场景
将一组对象组织成树形结构,以表示一种部分整体的层次结构。组合模式可以让客户端统一单个对象和组合对象的处理逻辑。
3,行为型设计模式
1,观察者模式
1,应用场景
- 1,将观察者和被观察者解耦
- 2,发布订阅模式有发布订阅中心(中间商),观察者模式没有。
2,实现
// 目标对象
class Subject {
observerList: Observer[]
constructor() {
this.observerList = [];
}
addObserver(observer) {
this.observerList.push(observer);
}
notify() {
this.observerList.forEach((observer) => {
observer.update();
});
}
}
// 观察者
class Observer {
cb: Function
constructor(cb: Function) {
if (typeof cb === "function") {
this.cb = cb;
} else {
throw new Error("Observer构造器必须传入函数类型!");
}
}
update() {
this.cb();
}
}
// test
const observerCallback = function () {
console.log("我被通知了");
};
const observer = new Observer(observerCallback);
const subject = new Subject();
subject.addObserver(observer);
subject.notify();