1.什么叫做设计模式(基本概念)
- 在面向对象软件设计过程中,针对问题进行简洁而优雅的一种解决方案
- 设计模式是在某种场合下对某个问题的一种解决方案
- 设计模式是在1995年初步形成,共有23种模式
①:创建型模式:单例模式,抽象工厂模式,建造者模式,工厂者模式,原型模式
②:结构型模式:适配器模式,桥接模式,装饰模式,组合模式,外观模式,亨元模式,代理模式,
③:行为型模式:模板方法模式,命令模式,迭代器模式,观察者模式,中介者模式,备忘录模式,解释器模式,状态模式,策略模式,职责链模式,访问者模式。
2.设计模式能干什么
- 设计模式最大的功绩就是:把已经存在好的设计提炼出来,并取了一个号的名字(GoF)
设计模式-创建型模式(之工厂者模式)
案列-四则运算
- 基本版本↓
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
input[type="text"]{
width: 100px;
}
</style>
</head>
<body>
<div style="width:500px;height:80px;margin:50px auto;border:2px solid #ddd;">
<input type="text" id="num1">
<select name="" id="operator">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" id="num2">
<input type="button" value='计算' id='btn'>
<input type="text" id="result">
</div>
<script>
function $(id){
return document.getElementById(id);
}
$('btn').onclick=function(){
//收集信息
var num1 = $("num1").value;
var num2 = $("num2").value;
//正则验证
var reg = /^[1-9]\d*$/;//正整数
if(reg.test(num1) && reg.test(num2)){
num1 = parseFloat(num1);
num2 = parseFloat(num2);
var op = $("operator").value;
var result;
//计算
if("+" == op){
result = num1 + num2;
}
else if("-" == op){
result = num1 - num2;
}
else if("*" == op){
result = num1 * num2;
}
else if("/" == op){
result = num1 / num2;
}
//显示结果
$("result").value = result;
console.info(num1,num2,op);
}
else{
alert("请输入正整数")
}
}
</script>
</body>
</html>
分析:在给一个运算符添加新功能时,会有一个安全隐患:全部的代码暴露在当前的程序员面前,同时,相当与是在修改源代码的方法去拓展一个新功能,但是这不符合“对修改关闭原则”
- 使用面向对象的版本↓
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
input[type="text"]{
width: 100px;
}
</style>
</head>
<body>
<div style="width:500px;height:80px;margin:50px auto;border:2px solid #ddd;">
<input type="text" id="num1">
<select name="" id="operator">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
<option value="%">%</option>
</select>
<input type="text" id="num2">
<input type="button" value='计算' id='btn'>
<input type="text" id="result">
</div>
<script>
function Add(num1,num2){
this.num1 = num1;
this.num2 = num2;
}
Add.prototype.getResult = function(){
return this.num1 + this.num2;
}
function Mul(num1,num2){
this.num1 = num1;
this.num2 = num2;
}
Mul.prototype.getResult = function(){
return this.num1 * this.num2;
}
function Div(num1,num2){
this.num1 = num1;
this.num2 = num2;
}
Div.prototype.getResult = function(){
if(this.num2 == 1){
return this.num1;
}
return this.num1 / this.num2;
}
function Sub(num1,num2){
this.num1 = num1;
this.num2 = num2;
}
Sub.prototype.getResult = function(){
return this.num1 - this.num2;
}
function Mod(num1,num2){
this.num1 = num1;
this.num2 = num2;
}
Mod.prototype.getResult = function(){
return this.num1 % this.num2;
}
function $(id){
return document.getElementById(id);
}
/**
* 功能:计算器
* @param {[type]} op [操作符]
* @param {[type]} num1 [第一个操作数]
* @param {[type]} num2 [第二个操作数]
* @return {[type]} [返回结果]
*/
function computer(op,num1,num2){
var c;
if("+" == op){
c = new Add(num1,num2);
}
else if("-" == op){
c = new Sub(num1,num2);
}
else if("*" == op){
c = new Mul(num1,num2);
}
else if("/" == op){
c = new Div(num1,num2);
}
else if("%" == op)
c = new Mod(num1,num2);
return c.getResult();
}
/**
* 正则验证
* @param {[type]} type [类型]
* @param {[type]} str [要验证的字符串]
* @return {[type]} [验证结果]
*/
function reg(type,str){
if( "number" == type){
var reg = /^[1-9]\d*$/;//正整数
return reg.test(str);
}
else if("email" == type ){
var reg = /^\w+@\w+(\.[a-z]{2,3})+$/i;
return reg.test(str);
}
}
$('btn').onclick=function(){
//收集信息
var num1 = $("num1").value;
var num2 = $("num2").value;
//正则验证
if(reg("number",num1) && reg("number",num2)){
num1 = parseFloat(num1);
num2 = parseFloat(num2);
var op = $("operator").value;
//计算
var result = computer(op,num1,num2);
//显示结果
$("result").value = result;
console.info(num1,num2,op);
}
else{
alert("请输入正整数")
}
}
</script>
</body>
</html>
分析:
- ①四个单独的运算器对象都可以在其他地方重复使用。
②在对新功能进行拓展的时候,不需要去暴露 其他功能的具体实现细节
③一个构造器就是一个单独的文件,它不会影响其他功能的构造器
总结:编写一个工厂函数,根据输入,返回特定的对象
设计模式-创建型模式(之单例模式)
- js字面量对象就是单例模式
需求:让一个构造器只产生一个对象
案列-按钮的单次点击(只能进行一次点击)
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
</style>
</head>
<body>
<input type="button" value="anniu" id="btn">
<script>
function $(id){
return document.getElementById(id);
}
//arguments
function f(){
console.info("我是事件响应函数");
}
function one(func){
var isclicked;
function f1(){
if(!isclicked){
func();
isclicked = true;
}
}
return f1;
}
$('btn').onclick=one(f);
</script>
</body>
</html>
总结:构造器的返回值,以及闭包的使用是对单例模型实现的一个完美体现
设计模式-行为模式(策略模式)
定义:把一系列的算法,封装起来,并且可以使它们可以相互替换
需求:给定一个值,进行求值
案列:计算公司员工的年终奖
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// 公司的年终奖是根据工资基数和绩效来发放的。例如绩效为S的员工有4倍工资。A的员工有3倍工资。B的员工有2倍工资。
// 请你给出代码
var salary = {
S:function(basic){
return 4 * basic;
},
A:function(basic){
return 3 * basic;
},
B:function(basic){
return 2 * basic;
},
C:function(basic){
return 1.5 * basic;
}
};
function getSalary(level,basic){
//var f1 = salary[level];
//return f1(basic);
return salary[level](basic);
}
console.info ( getSalary("S",10000) );
console.info ( getSalary("B",8000) );
console.info ( getSalary("C",6000) );
// console.info( salary("S",10000) );
// console.info( salary("C",6000) );
//问题:加一个等级C 1.5系数
</script>
</body>
</html>
总结:①保证了对修改的关闭,同时对拓展开放
②保证了代码之间的相互不影响
设计模式-行为模式(策略模式)
定义:观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
- 实现原理
观察者1,观察者2......
中心点
添加对象
删除观察者
发布更新指令(通知所有的观察者)
容器:保存观察者的数据 - 理论事例
案列
<html lang="en">
<head>
<meta charset="UTF-8">
<title>观察者模式</title>
</head>
<body>
<h1 id='header'>消息列表1条</h1>
<ul id="list">
<li>
消息内容<br><br>
<button value='删除' id='del'>删除</button>
</li>
</ul>
<input type="text" id='news'>
<button value='点击添加消息' id='btn'>点击添加消息</button>
</body>
<script>
function $(id){
return document.getElementById(id);
};
var counts=1;
$('del').onclick=function(){
counts--;
this.parentNode.parentNode.removeChild(this.parentNode);
$('header').innerHTML="消息列表"+counts+"条"
}
$('btn').onclick=function(){
var news=document.createElement('li'),
del=document.createElement('button');
news.innerHTML=$('news').value+'<br><br>';
del.innerHTML="删除";
del.onclick=function(){
counts--;
this.parentNode.parentNode.removeChild(this.parentNode);
$('header').innerHTML="消息列表"+counts+"条"
}
news.appendChild(del);
$('list').appendChild(news);
counts++;
$('header').innerHTML="消息列表"+counts+"条";
}
</script>
</html>
- 实践操作
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
.container{
border:3px solid #ccc;
padding:0 20px;
margin:30px auto;
width: 600px;
}
a{
text-decoration: none;
}
ul{list-style: none;}
</style>
</head>
<body>
<div class="container">
<h1>消息列表<span id="num">0</span>条</h1>
<ul id="ulmsg">
<!-- <li><p>消息内容</p><button>删除</button></li> -->
</ul>
<form action="">
<input type="text" id="words">
<input type="button" value="添加" id="btnsubmit">
</form>
</div>
<script type="text/javascript">
function $(id){
return document.getElementById(id);
}
function create(flag){
return document.createElement(flag)
}
//实现观察者
function NumberManager(data){
$("num").innerHTML = $("num").innerHTML*1 + data.num;
}
function MessageManager(data){
//<li><p>消息内容</p><button>删除</button></li>
var li = create("li");
var p = create("p");
var button = create("button");
button.innerHTML="删除";
button.onclick = function(){
$("ulmsg").removeChild(li);
center.fire("delMsg",{num:-1});
}
p.innerHTML = data.txt;
li.appendChild(p);
li.appendChild(button);
$("ulmsg").appendChild(li);
}
function Somthingelse(data){
console.info(data);
}
var center = {
viewers:{},
addViewer:function(eventtype,callback){
if(this.viewers.hasOwnProperty(eventtype)){
this.viewers[eventtype].push(callback);
}
else{
this.viewers[eventtype] = [callback];
}
},
delViewer:function(){
},
fire:function(eventtype,data){ //有变化 通知所有的观察者
if(this.viewers.hasOwnProperty(eventtype)){
for (var i = 0; i < this.viewers[eventtype].length; i++) {
this.viewers[eventtype][i].call(this,data);
}
}
}
}
center.addViewer("addMsg",Somthingelse); //添加订阅者
center.addViewer("addMsg",NumberManager);
center.addViewer("addMsg",MessageManager);
center.addViewer("delMsg",NumberManager);
$("btnsubmit").onclick = function(){
var data={
txt:$("words").value,
num:1
};
center.fire("addMsg",data);
}
</script>
</body>
</html>
设计模式-结构型模式(装饰者模式)
- 常见的需求
给对象动态地添加职责。在不改变对象自身的基础上,在程序运行期间给对象添加功能。比继承更灵活。 - 阐述思路
在不影响之前的代码下,给其添加新功能 - 问题的解决
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="jquery-2.1.4.js"></script>
</head>
<body>
<script type="text/javascript">
function ready(f){
debugger;
//判断一下window.onload是否存在 。如果存在 ,则先调用它,再调用f函数
var t = window.onload;
if(typeof t =="function"){
window.onload = function(){
t();
f();
}
}
else{
window.onload = function(){
f();
}
}
}
ready(function(){console.info(2)});
ready(function(){console.info(3)});
ready(function(){console.info(1)});
</script>
</body>
</html>
3.设计模式的利与弊
4.关于自学设计模式的浅略总结(坑)
设计模式“可复用面向对象软件的基础”。
设计模式完全是从面向对象设计的角度出发的,通过对封装、继承、多态、组合等技术的反复使用,提炼出一些可重复使用的面向对象设计技巧。所以有一种说法是设计模式仅仅是就面向对象的语言而言的。
网友评论