参考资料
设计原则(SOLID):
单一职责原则
开放/闭合原则
里氏替换原则
接口隔离原则
依赖倒置原则
迪米特法则
设计模式
创建型模式:
工厂模式(工厂,工厂方法,抽象工厂合并)
建造者模式
原型模式
单例模式
结构型模式:
适配器模式
桥接模式
装饰模式
外观模式
享元模式
代理模式
组合模式
行为型模式:
命令模式
中介者模式
观察者模式
状态模式
策略模式
https://www.cnblogs.com/swordfall/p/10742412.html
https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/creational.html
https://zhuanlan.zhihu.com/p/43283016
一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。
单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但有最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关经验。
一个软件实体应当对扩展开发,对修改关闭。即应尽量不修改源代码的情况下进行扩展
所有引用基类(父类)的地方必须要透明地使用其子类的对象。在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法。
使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
每个接口应当承担一种相对独立的角色,不干不该干的事,该干的事都要干。
接口仅仅提供客户端需要的行为,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口
在使用接口隔离原则时,我们需要注意控制接口的力度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护,接口也不能太大,太大的借口而将违背接口隔离原则,灵活性较差,使用起来不方便。
抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。要求我们再程序代码中传递参数时或在关联关系中,尽量应用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。
一个软件实体应当尽可能少地与其他实体发生相互作用。
当前对象本身、以参数形式传入到当前对象方法中的对象、当前对象的成员对象、如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友、当前对象所创建的对象。
应当尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用
在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,越有利于复用,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及;在类的结构设计上,每一个类都应当尽量降低其成员变量和成员属性的访问权限;在类的设计上,只要有可能,一个类型应当设计成不变类;在对其他类的引用上,一个对象对其他对象的引用应当降低到最低。
主要解决对象创建什么,由谁创建,何时创建的三大问题,对类的实例化进行了抽象,分离概念和实现,是的系统更加符合单一职责原则。
简介:工厂模式简言之就是要替代掉“new操作符”。因为有时候创建实例需要大量的准备工作,而将这些准备工作全部放在构造函数中是非常危险的行为,有必要将创建实例的逻辑和使用实例的逻辑分开,方便以后扩展。
typescript实现:如下封装,能清楚的分离对象的创建和使用,同时,如果之后类的定义发生改变,可以直接修改People,创建类的准备数据发生了改变,则修改工厂函数。
class People {
name: string = ''
age: number = 0
des: string = ''
constructor(name: string, age: number, des: string) {
this.name = name
this.age = age
this.des = des
}
}
async function peopleFactory(descriptioni:any) {
const name = await get('someUrl')
const age = await get('someUrl?name' + name)
const des = handle(description)
return new People(name, age, des)
}
(注意:使用工厂模式的原因是因为构造函数足够复杂或者对象的创建面临巨大的不确定性,只需要传入变量即可改造的情况下,使用工厂模式是得不偿失的。)
简介:用于直接构建复杂对象。
typescript实现:将创建实例的属性和方法都单独封装在一个类中
class PeopleConfigBuilder {
name: string = ''
age: nuber = 0
des: string = ''
async buildName(){
this.name = await get('someUrl')
}
async buildAge(){
this.age = await get('someUrl?name' + name)
}
async buildDes(description: any) {
this.des = handleDes(description)
}
}
class People {
name: string = ''
age: number = 0
des: string = ''
constructor(peopleConfig: PeopleConfigBuilder) {
this.name = peopleConfig.name
this.age = peopleConfig.age
this.des = peopleConfig.des
}
}
async function peopleFactory(description: any) {
const builder = new PeopleConfigBuilder()
builder.buildName()
builder.buildAge()
builder.buildDes()
return new People(builder)
}
简介:创建新对象时是基于一个对象拷贝,而不是重新实例化一个类
在上例中的peopleConfig其实应该是有固定模板的:
function peopleConfigPrototype () {
return {
name: '',
age: 0,
des: ''
}
}
这样每次返回都是新的对象,也相当于是对对象的拷贝,但直接拷贝对象,应该是以下写法:
const peopleConfigPrototype = {
name: '',
age: 0,
des: ''
}
const peopleConfig = Object.create(peopleConfigPrototype)
//使用object.create,当前对象将被复制到peopleConfig的__proto__上
简介:目的是限制一个类只能被实例化一次,防止多次实例化。其中,根据类被实例化的时间,又被分为懒汉单例和饿汉单例。懒汉单例是指在第一次调用实例的时候实例化。饿汉单例是指在类加载的时候就实例化。
//懒汉单例
class PeopleSingle {
//静态成员instance
static instance = null
//私有构造函数
private construcotr() {}
//第一次实例的时候实例化
public static getInstance(){
if(PeopleSingle.instance === null) {
PeopleSingle.instance = new PeopleSingle()
}
return PeopleSingle.instance
}
}
PeopleSingle.getInstance()
//饿汉单例
class PeopleSingle {
//类加载时就实例化了
static instance = new PeopleSingle()
private constructor() {}
}
描述如何将类或者对象组合在一起,形成更大的数据结构,因此也可以分为类结构型和对象结构型。
简介:实际上就是被适配对象上套上一层封装,将其接口与目标对象相匹配。
typescript实现:
//目标类UsbC
class UsbC {
slowCharge(){
console.log('slow chargin')
}
supperCharge() {
console.log('super charging')
}
}
//被适配目标MicroUsb
class MicroUsb {
slowCharge() {
console.log('slow charging')
}
}
//适配器adapter
class MicroToCAdapter implements UsbC {
microUsb: MicroUsb
constructor(miscroUsb: MicroUsb) {
this.microUsb = microUsb
}
slowCharge() {
this.microUsb.slowCharge()
}
superCharge(){
console.log('cannot super charge, slow charging')
}
}
new MicroToCAdapter(new MicroUsb()).superCharge()
简介:将抽象与实现解耦,使二者可以独立地进行变化,以应对不断更细的需求。
typescript实现:示例:汽车和颜色
//颜色抽象类
abstract class Color {
color: string
abstract draw(): void
}
//汽车抽象类
abstract class Car {
color: Color
abscract setColor(color: Color):void
}
//颜色实例
class Red extends Color {
constructor(){
super()
}
draw(){
this.color = 'red'
}
}
//汽车实例
class Van extends Car {
constructor(){
super()
}
setColor(color: Color){
this.color = color
}
}
//上述,抽象类和实现是解耦的,如果要利用所有类,就使用桥接类
class PaintingVanBridge {
var: Car
red: Color
constructor(){
this.red = new Red()
this.red.draw()
this.van = new Van()
this.van.setColor(this.red)
}
}
(桥接模式会增加大量代码,使用前需对功能模块有一个恰当的评估)
简介:在现有类或对象的基础上,添加了一些功能,使类和对象具有新的表现
typescript实现:继承上例Car,添加颜色
function colorDecorator(color: string){
return function (constructor: T){
return class extends constructor {
name = 'shit'
color = color
}
}
}
@colorDecorator('red')
class Car {
name: string
constructor(name: string){
this.name = name
}
}
(装饰器会拦截Car的构造函数,生成一个继承自Car的新的类,这样更加灵活(但这个过程只发生在构造函数阶段)
简介:“封装复杂,接口简单”,为所有的子系统提供一直的接口
class Tyre {
name: string
constructor(name: string){
this.name = name
}
}
class Steering {
turnRight(){}
turnLeft(){}
}
//统一接口
interface CarConfig{
tyrpName: string
ifTurnRight: boolean
}
class Car{
tyre: Tyre
steering: Steering
constructor(carConfig: CarConfig){
this.tyre = new Tyre(carConfig.name)
this.steering = new Steering()
if(CarConfig.ifTurnRight){
this.steering.turnRight
}
}
}
简介:避免重新创建对象,其实只要有缓存对象的意思,并且共用一个对象实例,就是仙缘模式
typescript实现:
class Car{
name: string
color: string
changeColor(color: string){
this.color = color
}
changeName(name: string){
this.name = name
}
}
class CarFactory {
static car: Car
static getCar():Car {
if(CarFactory.car === null){
CarFactory.car = new Car()
}
return CarFactory.car
}
}
CarFactory.getCar().changeColor('red')
简介:对接口进行一定程度的隐藏,用于封装复杂类
typescript实现:比如Car有很多属性,我们只需要一个简单的版本
class Car {
a: number = 1
b: number = 2
c: number = 3
d: number =4
name:string = 'name'
test(){
console.log('this is test')
}
}
class CarProxy {
private car: Car
name:number
constructor(){
if(this.car === null){
this.car = new Car
}
this.name = this.car.name
}
test(){
this.car.test()
}
}
简介:将对象组合成树形结构以表示“部分-整体”的层次结构。组合使得用户对单个对象和组合对象的使用具有一致性。
场景:文件目录
对不同的对象划分不同责任和算法的抽象,关注类和对象之间的相互作用,同样也分为类和对象。
简介:主要目的是让请求者和响应者解耦,并集中管理
function requestCommand(command: string){
let method = 'get'
let queryString = ''
let data = null
let url = ''
const commandArr = command.split('')
url = commandArr.find(el => el.indexOf('http'))
const methods = commandArr.filter(el=>el[0] === '-')
methods[0].replace('-', '')
method = methods[0]
const query = commandArr.filter(el=>el.indexOf('='))
if(query.length > 0){
queryString = '?'
query.forEach(el => {
queryStirng += el + '&'
})
}
const dataQuery = commandArr.filter(el=>el[0]==='{')
//对json判断
data = JSON.parse(dataQuery)
if(method === 'get' || method === 'delete'){
return axios[method](url + query)
}
return axios[method](url+query, data)
}
requestCommand('--get https://www.baidu.com name=1 test=2')
requestCommand('--post https://www.baidu.com {"name" = 1, "test":2}')
(命令模式需要提供详尽的文档,并且尽可能集中管理)
简介:全权负责两个模块之间的通讯,MVC,MVVM就是典型的中介模式
中介模式,桥接模式,代理模式的区别:
typescript实现:4s店、车和买家之间的关系
class Car {
name: string = 'Benz'
}
class Buyer {
name: string = 'Sam'
buy(car:Car){
console.log(`${this.name}购买了${car.name}`)
}
}
class FourSShop {
constructor(){
const benz = new Car()
const sam = new Buyer()
sam.buy(benz)
}
}
(可以想象中介模式是一个立体的概念,可以理解成两个概念发生关系的地点)
简介:为了“检测变更”,表示的是“记录事件”。既然要检测变更,自然需要记录之前的信息。vue的响应式原理也是使用观察者模式。
typescript实现
class Observer {
states: string[] = []
update(state: string) {
this.states.push(state)
}
}
class People {
state: string = ''
observer:Observer
setState(newState:string){
if(this.state !== newState){
this.state = newState
this.notify(this.state)
}
}
notify(state: string){
if(this.observer !== null){
this.observer.update(state)
}
}
setObserver(observer: Observer) {
this.observer = observer
}
}
const observer = new Observer()
const people = new People().setObserver(observer)
people.setState('shit')
console.log(observer.state)
简介:与观察者模式相对,表示的是“记录状态”,只要状态变更,表现及不同,这是设计数据驱动的基础
typescript实现:
class State {
tmp: string
set store(state: string){
if(this.tmp !== state){
this.tmp = state
}
}
get store(): string {
return this.tmp
}
}
class People {
state: State
constructor(state: State){
this.state = state
}
}
const state = new State()
const people = new People(state)
state.store = 1
console.log(people.state.store)
(如果一个数据接口即能记录事件,又能记录状态,就是响应式数据里)
简介:表示动态的修改行为,而行为有时候是一系列方法和对象的组合,与命令模式的区别也在这里。
typescript实现:从中国到罗马
class Location {
position: string
constructor(position: string){
this.position = position
}
}
class Stratege {
locations: Location [] = []
constructor(...locations){
this.locations = locations
console.log('路线经过了')
this.location.forEach(el=>{
console.log(el.position+ ',')
})
}
}
class Move {
start: Location
end: Location
stratege: Stratege
constructor(){
this.start = new Location('1 1')
this.end = new Location('0 0')
const sea = new Location('1 0')
const land = new Location('1 0')
this.stratege = new Stratege(this.start, sea, this.end)
}
}
(三大模式正好解决了编程中的数据结构从哪里来?如何组合?如何交流?的问题)