<!DOCTYPE html>
<html>
<head>
<title>新建网页</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<script type="text/javascript">
/*
思路:
1:在select上加一个onchange事件
2:当事件发生时,读取选中的值
3:判断
如果 是 男, 改内容区的背景为灰, 改广告区的内容为男性话题
如果 是 女, 改内容区的背景为粉, 改广告区的内容为女性话题
*/
</script>
<style type="text/css">
div {
padding:10px 0;
border: green 1px solid;
margin-top:20px;
}
</style>
</head>
<body>
<select name="gender" onchange="cstyle();">
<option value="m">男士风格</option>
<option value="f">女士风格</option>
</select>
<div id="content">
这是内容区,背景要随样式变
</div>
<div id="ad">
这是广告区,内容要变
</div>
<div id="footer"></div>
</body>
<script type="text/javascript">
function cstyle() {
var sel = document.getElementsByTagName('select')[0];
var curr = sel.options[sel.options.selectedIndex].value;
if(curr == 'm') {
document.getElementById('content').style.backgroundColor='gray';
document.getElementById('ad').innerHTML='足球 新闻 男装';
} else if(curr == 'f') {
document.getElementById('content').style.backgroundColor='pink';
document.getElementById('ad').innerHTML='LV, 减肥 韩剧';
}
}
/*
这个效果,通过上面的代码就实现了, 思路非常的中规中矩,面向过程,一步一步来.
分析不足:1:如果突然让你再选择风格时,还要影响到id="footer"的区
你怎么办?
2:再复杂一点,选择男性风格时,影响footer区,选女性,不影响footer区
思考:当select影响的区域变化时, 我们的cstyle函数,
尤其是if else段里的内容,要不断修改
从面向对象的角度来看:违反了"开闭原则".
开闭原则:对扩展是开放的, 对修改是封闭的.
从这个原则出发: 你想多监控footer区,那应该通过增加函数来实现,
但不能修改原函数来实现
思考:如何想监控新区域,是通过增加函数,而非修改函数?
想回答这样问题--你仍要思考,为什么我们当前的做法,是修改旧函数?
原因:我们if/else是判断客户的选择
而if/else里面的内容 却是实施对象操作.
就是说: 逻辑判决和判断后的操作,耦合的紧密了. 要解耦!
用什么思路来做:观察者模式来做
*/
</script>
</html>
<script type="text/javascript">
/*
还是刚才的同样功能,我们分析了其不足,
用观察者模式来做
什么叫观察者模式:
1:一个被观察者,当其发生变化时,把其最新信息传达给观察者
2:一个或多个观者者,发现被观察者变了,做相应的逻辑处理.
比如: 页面上有个天气预报, 隔5分钟刷新一下
如果天气变为"雨" ,页面底部显示 请注意带伞.
我们设1到多个对象,他们监控天气的变化.
天气变化,引起页面上其他部分的变化.
在此例中:
select是被观察者
2个div是观察者
一旦select变化,要把相应的信息投递到div中去,
供div观察.
*/
</script>
<style type="text/css">
div {
padding:10px 0;
border: green 1px solid;
margin-top:20px;
}
</style>
</head>
<body>
<select name="gender" onchange="cstyle();">
<option value="m">男士风格</option>
<option value="f">女士风格</option>
</select>
<div id="content">
这是内容区,背景要随样式变
</div>
<div id="ad">
这是广告区,内容要变
</div>
<div id="footer"></div>
<input type="button" onclick="detachad();" value="别监控广告区了" />
<input type="button" onclick="atfooter();" value="再多监控footer" />
</body>
<script type="text/javascript">
var sel = document.getElementsByTagName('select')[0]; //这是被观察者
var cont = document.getElementById('content'); // 这是2个观察者
var ad = document.getElementById('ad');
// 被观察者有什么变化,要通知到所有的观察者,供观察者分析并做操作.
// 把所有观察者注册进来
sel.observers = {};
// 给sel加一个注册方法,把观察他的对象,注册到他的observers"数组"上
sel.attach = function(key,observer) {
this.observers[key] = observer;
}
// 给sel加一个注销观察者的方法,作用与attach相反
sel.detach = function (key) {
delete this.observers[key];
}
// 如果我变化了,还要通知所有观察我的人,通知方法
sel.onchange = sel.notify = function () {
for(var k in this.observers) {
this.observers[k].update(this);
}
}
// 疑问: 你怎么知道,通知观察你的那些对象时,他们都有upload方法呢?
// 在js里没有接口这个概念
// 事实上,如果是java,php的话,要用观察者模式, 要先实现观察者的接口
// interface observer{update()} , interface observee {attach(),detach(),nofity()}
// 是有接口做强制规范的
cont.update = function (observee) {
if(observee.value == 'm') {
this.style.backgroundColor = 'gray';
} else if(observee.value == 'f') {
this.style.backgroundColor = 'pink';
}
}
ad.update = function (observee) {
if(observee.value == 'm') {
this.innerHTML = '岛国';
} else if(observee.value == 'f') {
this.innerHTML = '减肥';
}
}
document.getElementById('footer').update = function () {
this.innerHTML = '我只是证明我已经观察了'+Math.random();
}
/// ====== 服务端写完了 该客户端了=====///
sel.attach('cont',cont);
sel.attach('ad',ad);
// 我可以自由的增加或去掉1-2个监控
function detachad() {
sel.detach('ad');
}
function atfooter() {
sel.attach('footer',document.getElementById('footer'));
}
/*
思考:现在的做法,select的变化想多影响一个div或者dom对象
只需要把该dom对象注册成select的观察者
该观察会收到select的变化,并实施自己的update方法.
本质:判断逻辑 与 实施影响的逻辑 相分离
分离变化! 把变化单独分离出来,形成自己的逻辑.
从面向对象的角度看:
对象与对象之间,应该尽量通信,而不是控制.
*/
/*
观察者模式总结:
1:被观察者拥有attach,detach,notify接口
2:观察者拥有update方法
3: 把观察者注册到被观察者上,当被观者变化时, 把自身的变化 update通知到各观察者.
[至于观察者如何变化,那是他的事了,被观者不再操心了,实现了解耦]
本质: 解耦,分离变化
反思: 对象应该尽量通信,减少直接的控制.
*/
/***
作业:
设有如下场景:
用户登陆:
登陆成功了, 判断其邮箱,带不带vip.qq.com(看是不是Q会员,并做不同的处理)
登陆失败了, 记录其失败次数,并记住失败IP,等等.
这个过程,如果不用模式来做
if($login == true) {
// 判断邮箱..等等
} else if($login == false) {
记录失败次数,分析今天失败了几次,要不要出验证码........
}
// 你这个if /else 做的是不是有点多?
登陆模块,只负责判断登陆 true/false就够了.
至于成功失败的后续分析,你写那么多干吗?????
用---观察者模式来解决!
***/
</script>
</html>
转载于:https://my.oschina.net/u/2601503/blog/610379