S O L I D 五大设计原则
S———单一职责原则
O———开放封闭原则
L———李氏置换原则
I———-接口独立原则
D———-依赖导致原则
S———单一职责原则
O———开放封闭原则
L———李氏置换原则
I———-接口独立原则
D———-依赖导致原则
创建型
结构型
行为型
工厂模式是为了解决多个类似对象声明的问题;也就是为了解决实例化对象产生重复的问题。
代码演示
class Product{
constructor(name){
this.name = name
}
init(){alert('init')}
fun1(){alert('fun1')}
fun2(){alert('fun2')}
}
class Creator{
create(name){
return new Product(name)
}
}
//test
let create = new Creator()
let p = create.create('p1')
p.init()
p.fun1()
//init
//fun1
单例模式提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码可以通过单一变量进行访问。
单例模式是一个用来划分命名空间并将一批属性和方法组织在一起的对象,如果它可以被实例化,那么它只能被实例化一次。
代码演示
//单例模式
let Singleton = function (name) {
this.name = name
}
Singleton.prototype.getName = function () {
return this.name
}
//获取实例对象
let getInstance = (function () {
let instance = null
return function (name) {
if(!instance){
instance = new Singleton(name)
}
return instance
}
})()
//测试单例模式的实例
let a = getInstance('aa')
let b = getInstance('bb')
console.log(a === b) //true
console.log(a.getName()) //aa
console.log(b.getName()) //aa
//JQuery只有一个'$'
if(window.jQuery != null){
return window.jQuery
}else{
//初始化
}
//模拟登录框
class LoginForm{
constructor(){
this.state = 'hide'
}
show(){
if(this.state === 'show'){
alert('已经显示')
return
}
this.state = 'show'
console.log('登录框已显示')
}
hide(){
if(this.state === 'hide'){
alert('已经隐藏')
return
}
this.state = 'hide'
console.log('登录框已隐藏')
}
}
LoginForm.getInstance = (function () {
let instance
return function(){
if(!instance){
instance = new LoginForm()
}
return instance
}
})()
//test
let login1 = LoginForm.getInstance()
login1.show()
let login2 = LoginForm.getInstance()
login2.hide()
console.log('login1 === login2',login1 === login2)
解决两个软件实体间的接口不兼容的问题,对不兼容的部分进行适配
将一个类(对象)的接口(方法或属性)转化成另一个接口,以满足用户需求,使类(对象)之间接口的不兼容性问题通过适配器方法得以解决
代码演示
class Adaptee{
specificRequest(){
return '德国标准的插头'
}
}
class Target{
constructor(){
this.adaptee = new Adaptee()
}
request(){
let info = this.adaptee.specificRequest()
return `${info} -> 转换器 -> 中国标准的插头`
}
}
//text
let target = new Target()
target.request()
//封装旧接口
//自己封装的 ajax ,使用方式如下:
ajax({
url:'/getData',
type:'Post',
dataType:'json',
data:{
id:"123"
}
})
.done(function () {})
//但因为历史原因,代码中去都是
//$.ajax({...})
//做一层适配器
var $ = {
ajax:function (options) {
return this.ajax(options)
}
}
装饰者(decorator)模式能够在不改变对象自身的基础上,动态的给某个对象添加额外的职责,不会影响原有接口的功能。
代码演示
@testDec
class Demo{}
function testDec(target) {
target.isDec = true
}
alert(Demo.isDec)
代码演示
class ReadImg{
constructor(fileName){
this.fileName = fileName
this.loadFromDisk()
}
display(){
console.log('display...' + this.fileName)
}
loadFromDisk(){
console.log('loading...' + this.fileName)
}
}
class ProxyImg{
constructor(fileName){
this.realImg = new ReadImg(fileName)
}
display(){
this.realImg.display()
}
}
//test
let proxyImg = new proxyImg('1.png')
proxyImg.display()
//明星和经纪人
//明星
let star = {
name:'鞠婧祎',
age:25,
phone:'star : 13900001111'
}
//经纪人
let agent = new Proxy(star,{
get:function (target,key) {
if(key === 'phone'){
//返回经纪人自己的电话
return 'agent : 16899997777'
}
if(key === 'price'){
//明星不报价,经纪人报价
return 120000
}
return target[key]
},
set:function (target,key,val){
if(key === 'customPrice'){
if(val < 100000){
//最低10w
throw new Error('价格太低')
}else{
target[key] = val
return true
}
}
}
})
//test
console.log(agent.name)
console.log(agent.age)
console.log(agent.phone)
console.log(agent.price)
agent.customPrice = 150000
console.log('agent.customPrice',agent.customPrice)
不符合单一职责原则和开放封闭原则,因此谨慎使用,不可滥用
代码演示
function bindEvent(elem,type,selector,fn) {
if(fn == null){
fn = selector
selector = null
}
// ******
}
//调用
bindEvent(elem,'click','#div',fn)
bindEvent(elem,'click',fn)
观察者模式,通常也被叫做 发布-订阅模式
当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,解决了主体对象与观察者之间功能的耦合,即一个对象状态改变给其他对象通知的问题
代码演示
//主题,保存状态,状态变化之后触发所有观察者对象
class Subject{
constructor() {
this.state = 0
this.observers = []
}
getState(){
return this.state
}
setState(state){
this.state = state
this.notifyAllObservers()
}
notifyAllObservers(){
this.observers.forEach(observer => {
observer.update()
})
}
attach(observer){
this.observer.push(observer)
}
}
//观察者
class Observer{
constructor(name,subject){
this.name = name
this.subject = subject
this.subject.attach(this)
}
update(){
console.log(`${this.name} update,state : ${this.subject.getState()}`)
}
}
//测试
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)
s.setState(1)
s.setState(2)
s.setState(3)
代码演示
class Iterator{
constructor(container){
this.list = container.list
this.index = 0
}
next(){
if(this.hasNext()){
return this.list[this.index++]
}
return null
}
hasNext(){
if(this.index >= this.list.length){
return false
}
return true
}
}
class Container{
constructor(list){
this.list = list
}
//生成遍历器
getIterator(){
return new Iterator(this)
}
}
let container = new Container([1,2,3,4,5,6])
let iterator = container.getIterator()
while(iterator.hasNext()){
console.log(iterator.next())
}
以下不是前端重点掌握的设计模式
状态模式的关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变,同时把事物的每种状态都封装成单独的类。
代码演示
import StateMachine from 'javascript-state-machine'
import $ from 'jquery'
//初始化状态机模型
let fsm = new StateMachine({
init:'收藏',
transitions: [
{
name:'doState',
from:'收藏',
to:'取消收藏'
},
{
name:'deleteStore',
from:'取消收藏',
to:'收藏'
}
],
methods: {
//监听执行收藏
onDoStore:function () {
alert('收藏成功') //可以 post 请求
updateText()
},
//监听取消收藏
onDeleteStore:function () {
alert('已经取消收藏') //可以 post 请求
updateText()
}
}
})
let $btn = $('#btn1')
//按钮点击事件
$btn.click(function () {
if(fsm.is('收藏')){
fsm.doStore()
}else{
fsm.deleteStore()
}
})
//更新按钮的文案
function updateText() {
$btn.text(fsm.state)
}
//初始化文案
updateText()
原型模式是用来创建对象的一种模式。在以类为中心的语言中,要创建一个对象首先要指定这个对象的类型,然后实例化一个对象。使用原型模式创建对象时不必关心对象的具体类型,而是找到一个对象,然后通过克隆来创建一个一模一样的对象。所以在前者中如果要根据一个对象创建多个相同的对象,我们需要先保存这个对象的所有属性信息,然后将属性信息设置到新创建的对象上,而在原型模式中我们只需要使用克隆就能完成同样的功能。
代码演示
//'Object.create' 用到了原型模式的思想 (虽然不是Java中的clone)
//基于一个原型创建一个对象
var prototype = {
getName:function(){
return this.first + ' ' + this.last
},
say:function () {
console.log('hello')
}
}
//基于原型创建 x
var x = Object.create(prototype)
x.first = 'A'
x.last = 'B'
console.log(x.getName())
x.say()
//基于原型创建 y
var y = Object.create(prototype)
y.first = 'C'
y.last = 'D'
console.log(y.getName)
y.say()
对比JS中的prototype
prototype 可以理解为 ES6 class 的一种底层原理
而 class 是实现面向对象的基础,并不是服务于某个模式
ES6普及后大家可能会忽略到 prototype
但是 Object.create() 会长久存在
代码演示
class Color{
constructor(name){
this.name = name
}
}
class Shape{
constructor(name,color){
this.name = name
this.color = color
}
draw(){
console.log(`${this.color.name} ${this.name}`)
}
}
//测试代码
let red = new Color('red')
let yellow = new Color('yellow')
let circle = new Shape('circle',red)
circle.draw()
let triangle = new Shape('triangle',yellow)
triangle.draw()
代码演示
<div id="div" class="container">
<p>123p>
<p>456p>
div>
{
tag:'div',
attr:{
id:'div1',
className:'container'
},
children:{
{
tag:'p',
attr:{},
children:['123']
},
{
tag:'p',
attr:{},
children:['456']
}
}
}
代码演示
<div id="div1">
<a href="#">a1a>
<a href="#">a2a>
<a href="#">a3a>
<a href="#">a4a>
div>
//无限下拉列表,将事件代理到高层节点上
//如果都绑定到 标签,对内存开销太大
let div1 = document.getElementById('div1')
div1.addEventListener('click',function (e) {
let target = e.target
if(e.nodeName === 'A'){
alert(target.innerHTML)
}
})
代码演示
class OrdinaryUser{
buy(){
console.log('普通用户购买')
}
}
class MemberUser{
buy(){
console.log('会员用户购买')
}
}
class VipUser{
buy(){
console.log('vip 用户购买')
}
}
let u1 = new OrdinaryUser()
u1.buy()
let u2 = new MemberUser()
u2.buy()
let u3 = new VipUser()
u3.buy()
代码演示
class Action{
handle(){
handle1()
handle2()
handle3()
}
handle1(){
console.log('1')
}
handle2(){
console.log('2')
}
handle3(){
console.log('3')
}
}
代码演示
//请假审批,需要组长审批,经理审批,最后总监审批
class Action{
constructor(name){
this.name = name
this.nextAction = null
}
setNextAction(action){
this.nextAction = action
}
handle(){
console.log(`${this.name}审批`)
if(this.nextAction != null){
this.nextAction.handle()
}
}
}
let a1 = new Action('组长')
let a2 = new Action('经理')
let a3 = new Action('总监')
a1.setNextAction(a2)
a2.setNextAction(a3)
a1.handle()
代码演示
class Receiver{
exec(){
console.log('执行')
}
}
class Command{
constructor(receiver) {
this.receiver = receiver
}
cmd(){
console.log('触发命令')
this.receiver.exec()
}
}
class Invoker{
constructor(command){
this.command = command
}
invoke(){
console.log('开始')
this.command.cmd()
}
}
//士兵
let soldier = new Receiver()
//小号手
let trumpeter = new Command(soldier)
//将军
let general = new Invoker(trumpeter)
general.invoke()
代码演示
//备忘录
class Memento{
constructor(content){
this.content = content
}
getContent(){
return this.content
}
}
//备忘列表
class CareTaker{
constructor(){
this.list = []
}
add(memento){
this.list.push(memento)
}
get(index){
return this.list[index]
}
}
//编辑器
class Editor{
constructor(){
this.content = null
}
setContent(content){
this.content = content
}
getContent(){
return this.content
}
saveContentToMemento(){
return new Memento(this.content)
}
getContentFromMemento(memento){
this.content = memento.getContent()
}
}
//测试代码
let editor = new Editor()
let careTaker = new CareTaker()
editor.setContent('111')
editor.setContent('222')
careTaker.add(editor.saveContentToMemento()) //将当前内容备份
editor.setContent('333')
careTaker.add(editor.saveContentToMemento()) //将当前内容备份
editor.setContent('444')
console.log(editor.getContent())
editor.getContentFromMemento(careTaker.get(1)) //撤销
console.log(editor.getContent())
editor.getContentFromMemento(careTaker.get(0)) //撤销
console.log(editor.getContent())
代码演示
class A{
constructor(){
this.number = 0
}
setNumber(num,m){
this.number = num
if(m){
m.setB()
}
}
}
class B{
constructor(){
this.number = 0
}
setNumber(num,m){
this.number = num
if(m){
m.setA()
}
}
}
class Mediator{
constructor(a,b) {
this.a = a
this.b = b
}
setA(){
let number = this.b.number
this.a.setNumber(number * 100)
}
setB(){
let number = this.a.number
this.b.setNumber(number / 100)
}
}
//测试
let a = new A()
let b = new B()
let m = new Mediator(a,b)
a.setNumber(100,m)
console.log(a.number,b.number)
b.setNumber(100,m)
console.log(a.number,b.number)
访问者模式和解释器模式不介绍了,前端应用场景很少