首页 > 编程语言 >JavaScript设计模式-结构型设计模式

JavaScript设计模式-结构型设计模式

时间:2022-10-27 20:38:09浏览次数:51  
标签:function prototype return JavaScript element var 设计模式 id 结构型


结构型设计模式关注如何把类或者对象组合成为更大、更复杂的结构,简化设计。包含:外观模式、适配器模式、代理模式、装饰者模式、桥接模式、组合模式、享元模式

外观模式(套餐服务)Facade

为一组复杂的子系统接口提供一个更高级的统一接口,通过该接口对I系统接口的访问更容易。

例如:

/**
* 外观者模式
* @param {*} dom
* @param {*} type
* @param {*} fn
*/

function addEvent(dom,type,fn){
if (dom.addEventListener) {
dom.addEventListener(type,fn,false);
}else if(dom.attachEvent) {
dom.attachEvent('on'+type,fn);
}else{
dom['on'+type] = fn;
}
}

/**
* 简单的属性样式方法库
*/

var Dom = {
getID:function(id){
return document.getElementById(id);
},
css:function(id,key,value){
document.getElementById(id).style[key]=value;
},
attr:function(id,key,value){
document.getElementById(id)[key] = value;
},
html:function(id,html){
document.getElementById(id).innerHTML = html;
},
on:function(id,type,fn){
document.getElementById(id)['on'+type] = fn;
}
};


测试代码:

<body>
<input type="text" id="box">

<p id="text">duxin</p>
<script src="js/Facede.js"></script>

<script>
var box = document.getElementById("box");
addEvent(box,'click',function(){
console.log("事件1")
});

addEvent(box,"mouseenter",function(){
console.log("事件2")
})
addEvent(box, "click", function () {
console.log("事件3")
})

Dom.css('text','color','red');
Dom.html('text','读心');
Dom.on('text','click',function(){
console.log(1111)
})
</script>
</body>

外观模式的本质是:封装交互,简化调用

适配器模式(Adapter)

为了满足用户的需求,把一个类(对象)的接口(属性或者方法)转化为另一个接口,让对象(类)之间的接口不兼容问题通过适配器得以解决。

/**
* 适配异类框架
*/

//自定义框架
var D = D || {};

D.getID = function(id){
return document.getElementById(id);
}

// //在引入JQuery替换D代码库
// D.getID = function(id){
// return $(id).get(0)
// }


//给元素绑定事件
D.on = function(id,type,fn){
//传递参数是字符串就以id处理,否则以元素对象处理

var dom = typeof id === 'string' ? this.getID(id) : id;

//DOM2级添加事件
if (dom.addEventListener) {
dom.addEventListener(type,fn,false);
}else if (dom.attachEvent) {
dom.attachEvent('on'+type,fn);
}else{
dom['on'+type] = fn;
}
}

/**
* 参数适配器,当函数需要传入多个参数时,
* 通常是以一个参数对象的方式传入
*/
function doSomeThing(obj){
var _adapter = {
name:'读心',
title:"设计模式",
age:25,
color:"blue",
size:50,
prize:25
};
for(var i in _adapter){
_adapter[i] = obj[i] || _adapter[i]
}
}

/**
* 数据适配
*/

var arr = ['javascript','book','前端编程语言','2019-4-10'];

//把arr的数据适配成对象的形式,如:
function arrToObjAdapter(arr){
return{
name:arr[0],
type:arr[1],
title:arr[2],
data:arr[3]
}
}

/**
* 服务器端数据适配
*/

function ajaxAdapter(data) {
//处理并且返回新的数据
return [data['key1'],data['key2']]
}

$.ajax({
url:"",
success:function(data,status){
if (data) {
//使用适配后的数据(返回的对象)
doSomeThing(ajaxAdapter(data))
}
}
})

<body>
<input type="text" id="box">

<p id="text">duxin</p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="js/Facede.js"></script>
<script src="js/Adapter.js"></script>
<script>
var box = document.getElementById("box");
addEvent(box,'click',function(){
console.log("事件1")
});

addEvent(box,"mouseenter",function(){
console.log("事件2")
})
addEvent(box, "click", function () {
console.log("事件3")
})

Dom.css('text','color','red');
Dom.html('text','读心');
Dom.on('text','click',function(){
console.log(1111)
})

D.on(window,'load',function(){
D.on('box','click',function(){
console.log(165453)
})
});

var adapterData = arrToObjAdapter(arr);
console.log(adapterData)
</script>
</body>

代理模式(Proxy)

为其他对象提供一种代理,以便控制这个对象的访问。因为一个对象不能直接引用另外一个对象,而代理对象在两个对象之间起到了中介的作用。

比如用户相册模块上传照片量越大,则服务端需要把上传图片的模块重新部署到另外一个服务器(另外一个域)。那么在前端中用户上传图片的请求路径发生了变化,指向其他服务器而造成了跨域问题。

JavaScript对安全访问因素考虑,不允许跨域调用其他页面,而且还对同域名不同端口号、同域名不同协议、域名和域名对应的IP、主域名和子域名、子域名和子域名做了限制,不能直接调用。

JQuery核心代码中的代理模块

/**
* jQuery核心中的jQuery.proxy()方法
*/

//把函数绑定到上下文(context)上
var jQuery = {
proxy:function(fn,context){
if (typeof context === "string") {
var tmp = fn[context];
context = fn;
fn = tmp;
}
if (!jQuery.isFunction(fn)) {
return undefined;
}

//模拟绑定
var args = slice.call(arguments,2);
var proxy = function(){
return fn.applay(context,args.context(slice.call(arguments)));
};

proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
return proxy;
}
}

装饰者模式

促进代码复用,装饰者(Decorator)模式不太依赖创建对象的方式,更多的关注扩展对象的额外功能

/**
* Decorator 装饰者模式
* 新功能装饰构造函数
*/

//车辆构造函数
function vehicle(vehicleType){
this.vehicleType = vehicleType || 'car';
this.model = 'default';
this.license = "00000-000";
}

var test = new vehicle("car");
console.log(test);

var truck = new vehicle("truck");

//添加功能
truck.setModel = function(modelName){
this.model = modelName;
}

truck.setModel("CAT");


console.log(truck);

var test1 = new vehicle('car');
console.log(test1)


/**
* 被装饰的对象构造函数
*/

function MacBook(){
this.cost = function(){return 997;}
this.screenSize = function(){return 14;}
}

function Memory(macbook){
var v = macbook.cost();
macbook.cost = function(){
return v + 75;
};
}


function Engraving(macbook){
var v = macbook.cost();
macbook.cost = function(){
return v + 200;
};
}

function Insurance(macbook){
var v = macbook.cost();
macbook.cost = function(){
return v + 250;
}
}

var mb = new MacBook();

Memory(mb);

console.log(mb.cost());

console.log(mb.screenSize());


/**
* 接口
*/

var reminder = new Interface('List',["summary","placeOrder"]);

var properties = {
name: "duxin",
data:"2019/04/11",
actions:{
summary:function(){
return "remember"
},
placeOrder: function () {
return "Ordering "
}
}
};

function Todo(config){
Interface.ensureImplements(config.reminder);
this.name = config.name;
this.methods =config.actions;
}

//Todo实例
var todoItem = Todo(properties);

console.log(totItem.methods.summary());

桥接模式(Brideg)

在系统沿着多个维度变化时,又不能增加它的复杂度。但是页面中的一些细节的改变经常因为逻辑相似而导致代码大片臃肿。桥接模式就是把代码中相似的逻辑抽象出来。

/**
* 桥接模式
*/

function changeColor(dom,color,bg){
//设置元素的字体颜色
dom.style.color = color;

//设置元素的背景颜色
dom.style.background = bg;
}

//测试

span[0].onmouseout = function(){
changeColor(this,"#ddd","#909");
}

span[1].onmouseover =function(){
changeColor(this.getElementsByTagName("strong")[1],"#000","red")
}

/**
* 实例
*/

function Speed(x,y) {
this.x = x;
this.y = y;
}

Speed.prototype.run = function(){
console.log("开始走动");
}

function Color(cl){
this.color = cl;
}

Color.prototype.draw = function(){
console.log("绘制色彩");
}

function Shape(sp){
this.shape = sp;
}

Shape.prototype.change = function(){
console.log("边形")
}

//创建一个类
function Ball(x,y,c){
this.speed = new Speed(x,y);
this.color = new Color(c);
}

Ball.prototype.init = function(){
this.speed.run();

this.color.draw()
}

桥接模式就是把实现层(例如页面元素的绑定事件)和抽象层(修饰页面的UI逻辑)分离,两个部分独立变化。

组合模式

就是把对象组合成为树形结构来表示“部分整体”的层次结构

如:

/**
* 寄生式继承
*/
//原型继承
function inheritObject(o) {
function F() { }
F.prototype = o;
return new F();
}
/**
* 寄生组合式继承
* 终极继承者
* 参数 subClass 子类
* 参数 superClass 父类
*/

function inheritPrototype(subClass, superClass) {

var p = inheritObject(superClass.prototype);

//防止在重写子类原型导致子类的constructor属性被修改
p.constructor = subClass;

//设置子类原型
subClass.prototype = p;
};


/**
* 组合模式
* 新闻模块的实例
*/
var News = function(){
this.children = [];
this.element = null;
}

News.prototype = {
init:function(){
console.log("暂停服务")
},
add:function(){
console.log("方法")
},
getElement:function(){
console.log("重构方法")
}
}

//容器类的构造函数
var Container = function(id,parent){
News.call(this);
this.id = id;
this.parent = parent;

this.init();
}

//寄生式继承父类原型方法
inheritPrototype(Container,News);

//构建方法
Container.prototype.init = function(){
this.element = document.createElement("ul");
this.element.id = this.id;
this.element.className = "new-container";
}

Container.prototype.add = function(child){
this.children.push(child);

this.element.appendChild(child.getElement());
return this;
}

Container.prototype.getElement = function(){
return this.element;
}

//显示方法
Container.prototype.show = function(){
this.parent.appendChild(this.element);
}

//下层级的行成员集合,新闻组合体类的实现方法

var Item = function(classname){
News.call(this);
this.classname = classname || "";
this.init();
}

inheritPrototype(Item,News);
Item.prototype.init = function(){
this.element = document.createElement("li");
this.element.className = this.classname;
}

Item.prototype.add = function(child){
//在子元素中插入元素
this.children.push(child);

//插入当前组件元素树中
this.element.appendChild(child.getElement());
return this;
}

Item.prototype.getElement = function(){
return this.element;
}


var NewsGroup = function(classname){
News.call(this);
this.classname = classname || "";
this.init();
}

inheritPrototype(NewsGroup,News);

NewsGroup.prototype.init = function(){
this.element = document.createElement("div");
this.element.classname = this.classname;
}

NewsGroup.prototype.add = function(child){
this.children.push(child);

this.element.appendChild(child.getElement());
return this;
}

NewsGroup.prototype.getElement = function(){
return this.element;
}

var ImageNews = function(url,href,classname){
News.call(this);
this.url = url || '';
this.href = href || "#";
this.classname = classname || "normal";
this.init();
}

inheritPrototype(ImageNews,News);
ImageNews.prototype.init = function(){
this.element = document.createElement("a");
var img = new Image();
img.src = this.url;
this.element.appendChild(img);
this.element.className = "image-news "+this.classname;
this.element.href = this.href;
}

ImageNews.prototype.add = function(){}
ImageNews.prototype.getElement = function(){
return this.element;
}

//基类新闻
var IconNews = function(text,href,type){
News.call(this);
this.text = text || "";
this.href = href || "#";
this.type = type || "video";
this.init();
}

inheritPrototype(IconNews,News);
IconNews.prototype.init = function(){
this.element = document.createElement("a");
this.element.innerHTML = this.text;
this.element.href = this.href;
this.element.className = "icon "+this.type
}

IconNews.prototype.add = function(){}
IconNews.prototype.getElement = function(){
return this.element;
}

var EasyNews = function(text,href){
News.call(this);
this.text = text || "";
this.href = href = href || "";
this.init();
}

inheritPrototype(EasyNews,News);
EasyNews.prototype.init = function(){
this.element = document.createElement("a");
this.element.innerHTML = this.text;
this.element.href = this.href;
this.element.className = "text";
}

EasyNews.prototype.add = function(){}
EasyNews.prototype.getElement = function(){
return this.element;
}

var TypeNews = function(text,href,type,pos){
News.call(this);
this.text = text || "";
this.href = href || "";
this.typs = type || "";
this.pos = pos || "left";
this.init();
}
inheritPrototype(TypeNews,News);
TypeNews.prototype.init = function(){
this.element = document.createElement("a");
if (this.pos === "left") {
this.element.innerHTML = '['+this.type+']'+this.text;
}else{
this.element.innerHtml = this.text +' ['+this.type+']';
}

this.element.href = this.href;
this.element.className = "text"
}

TypeNews.prototype.add = function(){}
TypeNews.prototype.getElement = function(){
return this.element;
}


//测试
var new1 = new Container("news",document.body);

new1.add(
new Item("normal").add(
new IconNews("xdghdgfh","#","video")
)
).add(
new Item("normal").add(
new NewsGroup('has-img').add(
new ImageNews("http://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=%E8%AF%BB%E4%B9%A6%E4%BC%9A&step_word=&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined©right=undefined&cs=1237806382,2069296067&os=2466978500,905549571&simid=3484268445,337602749&pn=2&rn=1&di=84150&ln=1887&fr=&fmq=1554998108461_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=0&spn=0&pi=0&gsm=0&objurl=http%3A%2F%2Fimg.redocn.com%2Fsheji%2F20160203%2Fdushuhuiyouzhongguofenghaibao_5848794.jpg&rpstart=0&rpnum=0&adpicid=0&force=undefined","#","small")
).add(
new EasyNews("!!!!")
).add(
new EasyNews("@@@@")
)
)
).add(
new Item('normal').add(
new TypeNews(">>>","#","NBA","left")
)
).add(
new Item("normal").add(
new TypeNews("}}}}}}","#","CBA","right")
)
).show();

享元模式(Flyweight)

使用共享技术有效的支持大量的细粒度的对象,避免了对象拥有相同的内容造成多余的开销。

享元模式就是对数据、方法共享分离,将数据、方法分成内部数据、内部方法和外部数据、外部方法。

内部数据和内部方法指的是相似或者公有的数据和方法,将它们提取出来减少一些开销,提高性能。

var Flyweight = function(){
var created = [];
function create(){
var dom = document.createElement("div");
document.getElementById("container").appendChild(dom);

created.push(dom);

return dom;
}
return {
getDiv:function(){
if (created.length<5) {
return create();
}else{
var div = created.shift();
created.push(div);
return div;
}
}
}
}();


/**
* 简单的新闻分页
*/
var paper = 0;
var num = 5;
//新闻总条数
var len = article.length;
for(var i =0;i<5;i++){
if(article[i]){
Flyweight.getDiv().inerHTML = article[i];
}
}

//下一页
document.getElementById("next_page").onclick = function(){
if(article.length < 5) return;

var n = ++paper * num % len;
var j = 0;

for(;j<5;j++){
if(article[n+j]){
Flyweight.getDiv().innerHTML = article[n+j];
}else if(article[n+j-len]){
Flyweight.getDiv().innerHTML = article[n+j-len];
}else{
Flyweight.getDiv().innerHTML = "";
}
}
}

享元模式就是为了提高程序的执行效率和系统的性能。


标签:function,prototype,return,JavaScript,element,var,设计模式,id,结构型
From: https://blog.51cto.com/u_12344418/5801920

相关文章

  • JavaScript中的
    "=="和"==="运算符使用于比较两个值是否相等。都允许任意类型的操作数,若操作数相等则返回true,否则返回false。"===":严格相等运算符(恒等运算符),用来检测两个操作数是......
  • JavaScript中易忘的运算符
    eval()JavaScript通过全局函数eval()可以解释运行由JavaScript源码组成的字符串并且产生一个值。eval("25*4");//==100eval()是一个原本是一个函数,但是已经被当成运算符来......
  • JavaScript函数进阶
    JavaScript中函数是第一类对象。函数与对象共存,函数也可以被视为其他人一类型的JavaScript对象。函数能被变量引用、能以字面量形式声名,甚至可以作为函数参数进行传递。Java......
  • JavaScript数组的push()等方法的使用
        数组是值得有序集合。每个值在数组中有一个位置,用数字表示,叫做索引。JavaScript数组是无类型的:数组元素可以是任何类型,而且同一个数组中可以存在不同类型元素,甚......
  • 23种设计模式一些随笔
    适配器这种聚合关系的实现,一般将聚合对象(TFCard)类声明到聚合体(SDAdapterTF)中。SDAdapterTF.java//声明适配者类privateTFCardmtfCard;//利用有参构造方法聚......
  • 【笔记02】Javascript - 基本概念 - (语句、练习)
    Javascript基本概念:语句if、ifelsefor 循环while 循环dowhile 循环switchcasebreakcontinueif、ifelse语法:if(条件){语句}elseif(){语句}else{语句}条件成......
  • JavaScript进阶(Learning Records)
    背景:对JavaScript的深入学习参考:《JavaScript高级程序设计》《冴羽JavaScript深入》从原型到原型链prototypeprototype是每个函数都会有的属性functionPerson(){......
  • 浅谈PHP设计模式的单例模式
    简介:单例模式是创建型对象的一种,用于如何优雅的创建对象。让一个类最多产生一个对象。场景:只需要一个对象就能解决并且要使用多次的场景,比如框架的数据库连接。优点:......
  • 五种IO模型及设计模式
    下面就分别来介绍一下这5种IO模型的异同。1.阻塞IO模型最传统的一种IO模型,即在读写数据过程中会发生阻塞现象。当用户线程发出IO请求之后,内核会去查看数据是否就绪,如......
  • 设计模式-桥接模式
    将抽象部分与它的实现部分分离,使它们都可以独立地变化。将一个大抽象接口,分成多个小抽象接口,选择一个主抽象接口,持有其他接口地引用,继承变组合,组合地各个部分可以独立变化(......