您的当前位置:首页JavaScript设计模式之构造器模式(生成器模式)定义与用法实例分析

JavaScript设计模式之构造器模式(生成器模式)定义与用法实例分析

2023-12-07 来源:菲特宠物网

本文实例讲述了JavaScript设计模式之构造器模式(生成器模式)定义与用法。分享给大家供大家参考,具体如下:

工厂模式虽然解决了重复实例化的问题,但无法识别对象类型。

可以采用构造函数(构造方法)可用来创建特定的对象,可以解决工厂模式无法识别对象实例的问题。也就是说,使用构造函数的方法 ,即解决了重复实例化的问题 ,又解决了对象识别的问题。

构造器模式与工厂模式的不同之处在于:

① 构造函数方法没有显示的创建对象 (new Object())

② 直接将属性和方法赋值给 this 对象;

③ 没有 return 语句。

构造函数方法的规范:

① 函数名和实例化构造名相同且大写 (非强制,但有助于区分构造函数和普通函数);

② 通过构造函数创建对象,必须使用new运算符。

function Person(name, age) { this.name = name; this.age = age; this.showName = function() { alert(this.name); };}var person1 = new Person("Alice", 23);var person2 = new Person("Bruce", 22);

构造器模式的问题:每个方法都要在每个实例上重新创建一遍。

原因:JavaScript中的函数是对象,每定义一个函数,就是实例化了一个Funtion对象,因此,使用构造函数创建的每个实例都有一个同名的方法,但这些方法不是同一个Function的实例,因为不同实例上的同名函数是不相等的。

解决:原型模式,请见://www.gxlcms.com/article/144485.htm

更多关于JavaScript相关内容可查看本站专题:《javascript面向对象入门教程》、《JavaScript切换特效与技巧总结》、《JavaScript查找算法技巧总结》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

小编还为您整理了以下内容,可能对您也有帮助:

设计模式-生成器模式《六》

定义:将一个复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的表现

1、需要创建涉及各种部件的复杂对象。创建对象的算法应该于部件的装配方式。常见例子是构建组合对象

2、构建过程需要以不同的方式(例如,部件或表现的不同组合)构建对象

生成器模式:

构建复杂对象

以多个步骤构建对象

以多种方式构建对象

在构建过程的最后一步返回产品

专注一个特定产品

工厂模式:

构建简单或复杂对象

以单一步骤构建对象

以单一方式构建对象

立刻返回产品

强调一套产品

Objective-C项目地址

JS常用设计模式(MVC、MVP、MVVM及其他设计模式)

一、MVC

MVC模式的意思是,软件可以分成三个部分。

视图(View):用户界面。

控制器(Controller):业务逻辑

模型(Model):数据保存

各部分之间的通信方式如下。

View 传送指令到 Controller

Controller 完成业务逻辑后,要求 Model 改变状态

Model 将新的数据发送到 View,用户得到反馈

所有通信都是单向的。

二、互动模式

接受用户指令时,MVC 可以分成两种方式。一种是通过 View 接受指令,传递给 Controller。

另一种是直接通过controller接受指令。

三、实例:Backbone

实际项目往往采用更灵活的方式,以 Backbone.js 为例。

1. 用户可以向 View 发送指令(DOM 事件),再由 View 直接要求 Model 改变状态。

2. 用户也可以直接向 Controller 发送指令(改变 URL 触发 hashChange 事件),再由 Controller 发送给 View。

3. Controller 非常薄,只起到路由的作用,而 View 非常厚,业务逻辑都部署在 View。所以,Backbone 索性取消了 Controller,只保留一个 Router(路由器) 。

四、MVP

MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。

1. 各部分之间的通信,都是双向的。

2. View 与 Model 不发生联系,都通过 Presenter 传递。

3. View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

五、MVVM

MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。

唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。 Angular 和 Ember 都采用这种模式。

1、js工厂模式

说明:

在函数中定义对象,并定义对象的各种属性,虽然属性可以为方法,但是建议将属性为方法的属性定义到函数之外,这样可以避免重复创建该方法。

引用该对象的时候,这里使用的是 var x = Parent()而不是 var x = new object(); 因为后者可能会出现很多问题(前者也成为工厂经典方式,后者称之为混合工厂方式),不推荐使用new的方式使用该对象。

在函数的最后返回该对象。

不推荐使用这种方式创建对象,但应该了解。  

2、js构造函数模式

说明:

与工厂方式相比,使用构造函数方式创建对象无需在函数内部创建对象,而使用this指代,并而函数无需明确return。

同工厂模式一样,虽然属性的值可以为方法,仍建议将该方法定义在函数之外。

同样的,不推荐使用这种方式创建对象,但仍需了解。

3、js原型模式

说明:

函数中不对属性进行定义。

利用prototype属性对属性进行定义。

同样的额,不推荐使用这样的方式创建对象。

4、构造函数+原型的js混合模式(推荐)

说明:

该模式是指混合搭配使用构造函数和原型方式。

将所有的属性,不是方法的定义在函数中(构造函数的方式),将所有属性值为方法的利用prototype在函数之外定义(原型方式)。

推荐使用这样的方式创建对象,这样有好处。

5、构造函数+原型的动态原型模式(推荐)

说明:

动态原型方式可以理解为混合构造函数,原型方式的一个特例。

该模式中,属性为方法的属性直接在函数中进行了定义,但是因为

if(typeof Parent.lev == "undefined"){

          Parent.prototype.lev = function(){

            return this.name;

          }

   Parent.lev = true;

    } 

从而保证创建该对象的实例时,属性的方法不会被重复的创建。

JS常用设计模式(MVC、MVP、MVVM及其他设计模式)

一、MVC

MVC模式的意思是,软件可以分成三个部分。

视图(View):用户界面。

控制器(Controller):业务逻辑

模型(Model):数据保存

各部分之间的通信方式如下。

View 传送指令到 Controller

Controller 完成业务逻辑后,要求 Model 改变状态

Model 将新的数据发送到 View,用户得到反馈

所有通信都是单向的。

二、互动模式

接受用户指令时,MVC 可以分成两种方式。一种是通过 View 接受指令,传递给 Controller。

另一种是直接通过controller接受指令。

三、实例:Backbone

实际项目往往采用更灵活的方式,以 Backbone.js 为例。

1. 用户可以向 View 发送指令(DOM 事件),再由 View 直接要求 Model 改变状态。

2. 用户也可以直接向 Controller 发送指令(改变 URL 触发 hashChange 事件),再由 Controller 发送给 View。

3. Controller 非常薄,只起到路由的作用,而 View 非常厚,业务逻辑都部署在 View。所以,Backbone 索性取消了 Controller,只保留一个 Router(路由器) 。

四、MVP

MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。

1. 各部分之间的通信,都是双向的。

2. View 与 Model 不发生联系,都通过 Presenter 传递。

3. View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

五、MVVM

MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。

唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。 Angular 和 Ember 都采用这种模式。

1、js工厂模式

说明:

在函数中定义对象,并定义对象的各种属性,虽然属性可以为方法,但是建议将属性为方法的属性定义到函数之外,这样可以避免重复创建该方法。

引用该对象的时候,这里使用的是 var x = Parent()而不是 var x = new object(); 因为后者可能会出现很多问题(前者也成为工厂经典方式,后者称之为混合工厂方式),不推荐使用new的方式使用该对象。

在函数的最后返回该对象。

不推荐使用这种方式创建对象,但应该了解。  

2、js构造函数模式

说明:

与工厂方式相比,使用构造函数方式创建对象无需在函数内部创建对象,而使用this指代,并而函数无需明确return。

同工厂模式一样,虽然属性的值可以为方法,仍建议将该方法定义在函数之外。

同样的,不推荐使用这种方式创建对象,但仍需了解。

3、js原型模式

说明:

函数中不对属性进行定义。

利用prototype属性对属性进行定义。

同样的额,不推荐使用这样的方式创建对象。

4、构造函数+原型的js混合模式(推荐)

说明:

该模式是指混合搭配使用构造函数和原型方式。

将所有的属性,不是方法的定义在函数中(构造函数的方式),将所有属性值为方法的利用prototype在函数之外定义(原型方式)。

推荐使用这样的方式创建对象,这样有好处。

5、构造函数+原型的动态原型模式(推荐)

说明:

动态原型方式可以理解为混合构造函数,原型方式的一个特例。

该模式中,属性为方法的属性直接在函数中进行了定义,但是因为

if(typeof Parent.lev == "undefined"){

          Parent.prototype.lev = function(){

            return this.name;

          }

   Parent.lev = true;

    } 

从而保证创建该对象的实例时,属性的方法不会被重复的创建。

24种设计模式

一、创建型模式 

1、抽象工厂模式(Abstract factory pattern): 提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类. 

2、生成器模式(Builder pattern): 使用生成器模式封装一个产品的构造过程, 并允许按步骤构造. 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示. 

3、工厂模式(factory method pattern): 定义了一个创建对象的接口, 但由子类决定要实例化的类是哪一个. 工厂方法让类把实例化推迟到子类. 

4、原型模式(prototype pattern): 当创建给定类的实例过程很昂贵或很复杂时, 就使用原形模式. 

5、单例了模式(Singleton pattern): 确保一个类只有一个实例, 并提供全局访问点. 

6、多例模式(Multition pattern): 在一个解决方案中结合两个或多个模式, 以解决一般或重复发生的问题. 

二、结构型模式 

1、适配器模式(Adapter pattern): 将一个类的接口, 转换成客户期望的另一个接口. 适配器让原本接口不兼容的类可以合作无间. 对象适配器使用组合, 类适配器使用多重继承. 

2、桥接模式(Bridge pattern): 使用桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变. 

3、组合模式(composite pattern): 允许你将对象组合成树形结构来表现”整体/部分”层次结构. 组合能让客户以一致的方式处理个别对象以及对象组合. 

4、装饰者模式(decorator pattern): 动态地将责任附加到对象上, 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案. 

5、外观模式(facade pattern): 提供了一个统一的接口, 用来访问子系统中的一群接口. 外观定义了一个高层接口, 让子系统更容易使用. 

6、亨元模式(Flyweight Pattern): 如想让某个类的一个实例能用来提供许多”虚拟实例”, 就使用蝇量模式. 

7、代理模式(Proxy pattern): 为另一个对象提供一个替身或占位符以控制对这个对象的访问. 

三、行为型模式 

1、责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象. 

2、命令模式(Command pattern): 将”请求”封闭成对象, 以便使用不同的请求,队列或者日志来参数化其他对象. 命令模式也支持可撤销的操作. 

3、解释器模式(Interpreter pattern): 使用解释器模式为语言创建解释器. 

4、迭代器模式(iterator pattern): 提供一种方法顺序访问一个聚合对象中的各个元素, 而又不暴露其内部的表示. 

5、中介者模式(Mediator pattern) : 使用中介者模式来集中相关对象之间复杂的沟通和控制方式. 

6、备忘录模式(Memento pattern): 当你需要让对象返回之前的状态时(例如, 你的用户请求”撤销”), 你使用备忘录模式. 

7、观察者模式(observer pattern): 在对象之间定义一对多的依赖, 这样一来, 当一个对象改变状态, 依赖它的对象都会收到通知, 并自动更新. 

8、状态模式(State pattern): 允许对象在内部状态改变时改变它的行为, 对象看起来好象改了它的类. 

9、策略模式(strategy pattern): 定义了算法族, 分别封闭起来, 让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户. 

10、模板方法模式(Template pattern): 在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤. 

11、访问者模式(visitor pattern): 当你想要为一个对象的组合增加新的能力, 且封装并不重要时, 就使用访问者模式.

24种设计模式

一、创建型模式 

1、抽象工厂模式(Abstract factory pattern): 提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类. 

2、生成器模式(Builder pattern): 使用生成器模式封装一个产品的构造过程, 并允许按步骤构造. 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示. 

3、工厂模式(factory method pattern): 定义了一个创建对象的接口, 但由子类决定要实例化的类是哪一个. 工厂方法让类把实例化推迟到子类. 

4、原型模式(prototype pattern): 当创建给定类的实例过程很昂贵或很复杂时, 就使用原形模式. 

5、单例了模式(Singleton pattern): 确保一个类只有一个实例, 并提供全局访问点. 

6、多例模式(Multition pattern): 在一个解决方案中结合两个或多个模式, 以解决一般或重复发生的问题. 

二、结构型模式 

1、适配器模式(Adapter pattern): 将一个类的接口, 转换成客户期望的另一个接口. 适配器让原本接口不兼容的类可以合作无间. 对象适配器使用组合, 类适配器使用多重继承. 

2、桥接模式(Bridge pattern): 使用桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变. 

3、组合模式(composite pattern): 允许你将对象组合成树形结构来表现”整体/部分”层次结构. 组合能让客户以一致的方式处理个别对象以及对象组合. 

4、装饰者模式(decorator pattern): 动态地将责任附加到对象上, 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案. 

5、外观模式(facade pattern): 提供了一个统一的接口, 用来访问子系统中的一群接口. 外观定义了一个高层接口, 让子系统更容易使用. 

6、亨元模式(Flyweight Pattern): 如想让某个类的一个实例能用来提供许多”虚拟实例”, 就使用蝇量模式. 

7、代理模式(Proxy pattern): 为另一个对象提供一个替身或占位符以控制对这个对象的访问. 

三、行为型模式 

1、责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象. 

2、命令模式(Command pattern): 将”请求”封闭成对象, 以便使用不同的请求,队列或者日志来参数化其他对象. 命令模式也支持可撤销的操作. 

3、解释器模式(Interpreter pattern): 使用解释器模式为语言创建解释器. 

4、迭代器模式(iterator pattern): 提供一种方法顺序访问一个聚合对象中的各个元素, 而又不暴露其内部的表示. 

5、中介者模式(Mediator pattern) : 使用中介者模式来集中相关对象之间复杂的沟通和控制方式. 

6、备忘录模式(Memento pattern): 当你需要让对象返回之前的状态时(例如, 你的用户请求”撤销”), 你使用备忘录模式. 

7、观察者模式(observer pattern): 在对象之间定义一对多的依赖, 这样一来, 当一个对象改变状态, 依赖它的对象都会收到通知, 并自动更新. 

8、状态模式(State pattern): 允许对象在内部状态改变时改变它的行为, 对象看起来好象改了它的类. 

9、策略模式(strategy pattern): 定义了算法族, 分别封闭起来, 让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户. 

10、模板方法模式(Template pattern): 在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤. 

11、访问者模式(visitor pattern): 当你想要为一个对象的组合增加新的能力, 且封装并不重要时, 就使用访问者模式.

设计模式(三)创建型模式

根据菜鸟教程的目录,我们首先来看看创建型模式。 创建型模式研究:

下面分别对创建型模式下的各种具体模式进行讲解。

先看例子: 工厂模式。

某功能的使用者只和接口打交道,不关心如何实现。这种情况下,肯定有一个接口类,使用者使用接口;功能提供者继承并实现接口。这利用了C++的多态特性。

既然使用者只关心接口,那么没有必要把子类直接给使用者,没有必要让使用者在代码中直接new子类。如果这样做,会把不必要的信息暴露给使用者,增加了信息的耦合。试想,如果使用者在很多地方都new了子类,那么如果这些地方需要修改的话,怎么改?只能一个一个地方改,改完还需要编译,维护极其困难。

工厂模式是指,针对某一功能接口,我们要新建一个工厂类,此工厂类将接口子类名称、接口子类的创建过程封装起来,只返回一个接口指针给接口的使用者。接口的实现类对使用者完全透明,高度解耦。这样可以方便地切换接口的具体实现,而不影响上层功能使用者。拿 汽车 打比方,不管工厂生产 汽车 的流程是什么,只要是 汽车 ,它的驾驶方法(人机接口)都类似。

显而易见,工厂模式在使用者和实现者之间增加了一个封装层,这正印证了计算机行业中一句名言:

典型的例子是:Qt中的数据库模块就利用了工厂模式,封装了数据库的底层实现。在保持数据库用户接口不变的情况下,通过更换数据库驱动,可以实现数据库类型无缝切换。

在需求趋于稳定时使用,需求不稳定时,不要过度设计,否则设计很容易被推翻,白费力气。

从设计模式的本质来看,工厂模式:

先看例子: 抽象工厂模式。

由前面工厂模式可知,所有的“工厂”有一个共同点:每个工厂都会提供创建对象的函数。 既然所有工厂都实现了同一类功能,那么我们可以为工厂抽象出一个公共接口(虚基类),此接口定义了创建工厂子类的功能。 这种场景是否似曾相识?是的,工厂和工厂的功能接口构成了使用工厂模式的场景。即工厂本身也适用于工厂模式。 使用工厂模式来设计工厂,必然要写一个生产工厂的工厂。 生产工厂的工厂,返回值是工厂的抽象接口类,所以这种设计模式叫“抽象工厂模式”。其实,笔者觉得把这种设计模式叫做“工厂工厂模式”更容易理解。

如果只有一个工厂就不要使用抽象工厂模式了,只有在工厂很多时,才使用抽象工厂模式。

需求不稳定时,不要过度设计,一切都可能被推翻。 对于小的项目,不需要过度追求使用设计模式,架构的代码最好只占整个项目代码的一小部分,否则就是主次颠倒,给自己找麻烦。 对于大的项目,在需求较稳定的情况下,为了提高可维护性、扩展性,可以考虑使用设计模式。 另外,抽象工厂模式有一定的理解难度,要考虑你设计的代码,其他人是否能够读懂,简单易懂也是需要考虑的方面。

所以,从设计模式的本质来看,

先看例子: 单例模式。

上面的例子都是允许一个类被创建多次的。如果我们想要*一个类只被创建一次,即只有一个全局可访问的实例(和C语言中的全局变量一样),例如应用程序对象,每个应用程序都应该只有一个应用程序对象。此时应该怎么编写代码呢?

答案还是封装。把不想暴露出来的信息藏起来,把必须暴露的信息暴露出来。单例模式把类的构造函数设置成private私有访问权限,*外部无法通过new来创建实例。只能通过特定的接口来获取实例指针。需要提及的是,封装时需要考虑多线程安全的问题。

当一个类需要有多个实例存在时,不使用单例模式。

从设计模式的本质上看,

具体的例子和写法,可以参考菜鸟教程中的 建造者模式。

建造者模式的典型使用场景是快餐店的套餐搭配模型。 套餐由若干个单个餐品组合而成。单个餐品又由不同的原材料构成。这种层层组合的树形对象关系的应用场景下,为了创建顶层的对象,需要先一层层的创建底层的对象,逐步向上,直到构造出根对象。 这种场景下,使用继承可以将同类的对象关联起来,使用组合可以将不同类型的对象组合起来。组合就是把不同对象放在一块内存中保存,作为一个整体使用。

完全使用继承来解决此类问题是非常不提倡的。设计模式理论中有一个原则是:“少用继承,多用组合”。因为继承是一种强耦合,组合是一种松散的耦合。耦合不利于适应需求变化,是项目中的一颗定时*。

从设计模式的本质上看,

菜鸟教程中没有提及的一种设计模式是组合模式。具体内容可以参考: 第四节:组合模式和建筑者模式详解。

这里简单说明一下,组合模式和建造者模式比较像,也是遵循树形对象关系结构。和建造者模式相比,不同之处在于,子对象和父对象具有相同的类型。所以可以说,组合模式是简单的建造者模式。

具体的使用场合和实例,见原型模式。

原型模式,在实际使用时可能用得不多。用一句话描述其特点:

这种克隆是一种内存中的复制行为,速度快,能充分利用已有对象的缓存数据,性能高。克隆出来的对象具有和原对象相同的属性和行为,可以用来帮助原对象处理一些事务。用一句动漫中的词汇来描述,“影分身”再合适不过了。

从设计模式的本质看,

下一篇,我们将介绍结构型模式。

设计模式(三)创建型模式

根据菜鸟教程的目录,我们首先来看看创建型模式。 创建型模式研究:

下面分别对创建型模式下的各种具体模式进行讲解。

先看例子: 工厂模式。

某功能的使用者只和接口打交道,不关心如何实现。这种情况下,肯定有一个接口类,使用者使用接口;功能提供者继承并实现接口。这利用了C++的多态特性。

既然使用者只关心接口,那么没有必要把子类直接给使用者,没有必要让使用者在代码中直接new子类。如果这样做,会把不必要的信息暴露给使用者,增加了信息的耦合。试想,如果使用者在很多地方都new了子类,那么如果这些地方需要修改的话,怎么改?只能一个一个地方改,改完还需要编译,维护极其困难。

工厂模式是指,针对某一功能接口,我们要新建一个工厂类,此工厂类将接口子类名称、接口子类的创建过程封装起来,只返回一个接口指针给接口的使用者。接口的实现类对使用者完全透明,高度解耦。这样可以方便地切换接口的具体实现,而不影响上层功能使用者。拿 汽车 打比方,不管工厂生产 汽车 的流程是什么,只要是 汽车 ,它的驾驶方法(人机接口)都类似。

显而易见,工厂模式在使用者和实现者之间增加了一个封装层,这正印证了计算机行业中一句名言:

典型的例子是:Qt中的数据库模块就利用了工厂模式,封装了数据库的底层实现。在保持数据库用户接口不变的情况下,通过更换数据库驱动,可以实现数据库类型无缝切换。

在需求趋于稳定时使用,需求不稳定时,不要过度设计,否则设计很容易被推翻,白费力气。

从设计模式的本质来看,工厂模式:

先看例子: 抽象工厂模式。

由前面工厂模式可知,所有的“工厂”有一个共同点:每个工厂都会提供创建对象的函数。 既然所有工厂都实现了同一类功能,那么我们可以为工厂抽象出一个公共接口(虚基类),此接口定义了创建工厂子类的功能。 这种场景是否似曾相识?是的,工厂和工厂的功能接口构成了使用工厂模式的场景。即工厂本身也适用于工厂模式。 使用工厂模式来设计工厂,必然要写一个生产工厂的工厂。 生产工厂的工厂,返回值是工厂的抽象接口类,所以这种设计模式叫“抽象工厂模式”。其实,笔者觉得把这种设计模式叫做“工厂工厂模式”更容易理解。

如果只有一个工厂就不要使用抽象工厂模式了,只有在工厂很多时,才使用抽象工厂模式。

需求不稳定时,不要过度设计,一切都可能被推翻。 对于小的项目,不需要过度追求使用设计模式,架构的代码最好只占整个项目代码的一小部分,否则就是主次颠倒,给自己找麻烦。 对于大的项目,在需求较稳定的情况下,为了提高可维护性、扩展性,可以考虑使用设计模式。 另外,抽象工厂模式有一定的理解难度,要考虑你设计的代码,其他人是否能够读懂,简单易懂也是需要考虑的方面。

所以,从设计模式的本质来看,

先看例子: 单例模式。

上面的例子都是允许一个类被创建多次的。如果我们想要*一个类只被创建一次,即只有一个全局可访问的实例(和C语言中的全局变量一样),例如应用程序对象,每个应用程序都应该只有一个应用程序对象。此时应该怎么编写代码呢?

答案还是封装。把不想暴露出来的信息藏起来,把必须暴露的信息暴露出来。单例模式把类的构造函数设置成private私有访问权限,*外部无法通过new来创建实例。只能通过特定的接口来获取实例指针。需要提及的是,封装时需要考虑多线程安全的问题。

当一个类需要有多个实例存在时,不使用单例模式。

从设计模式的本质上看,

具体的例子和写法,可以参考菜鸟教程中的 建造者模式。

建造者模式的典型使用场景是快餐店的套餐搭配模型。 套餐由若干个单个餐品组合而成。单个餐品又由不同的原材料构成。这种层层组合的树形对象关系的应用场景下,为了创建顶层的对象,需要先一层层的创建底层的对象,逐步向上,直到构造出根对象。 这种场景下,使用继承可以将同类的对象关联起来,使用组合可以将不同类型的对象组合起来。组合就是把不同对象放在一块内存中保存,作为一个整体使用。

完全使用继承来解决此类问题是非常不提倡的。设计模式理论中有一个原则是:“少用继承,多用组合”。因为继承是一种强耦合,组合是一种松散的耦合。耦合不利于适应需求变化,是项目中的一颗定时*。

从设计模式的本质上看,

菜鸟教程中没有提及的一种设计模式是组合模式。具体内容可以参考: 第四节:组合模式和建筑者模式详解。

这里简单说明一下,组合模式和建造者模式比较像,也是遵循树形对象关系结构。和建造者模式相比,不同之处在于,子对象和父对象具有相同的类型。所以可以说,组合模式是简单的建造者模式。

具体的使用场合和实例,见原型模式。

原型模式,在实际使用时可能用得不多。用一句话描述其特点:

这种克隆是一种内存中的复制行为,速度快,能充分利用已有对象的缓存数据,性能高。克隆出来的对象具有和原对象相同的属性和行为,可以用来帮助原对象处理一些事务。用一句动漫中的词汇来描述,“影分身”再合适不过了。

从设计模式的本质看,

下一篇,我们将介绍结构型模式。

Java开发中的23种设计模式详解(转)_Java开发模式

设计模式(Design Patterns)

——可复用面向对象软件的基础

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

一、设计模式的分类

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下:

二、设计模式的六大原则

1、开闭原则(Open Close Principle)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。

里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。

LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Bai 百科

3、依赖倒转原则(Dependence Inversion Principle)

这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle)

为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

原则是尽量使用合成/聚合的方式,而不是使用继承。

三、Java的23中设计模式

从这一块开始,我们详细介绍Java中23种设计模式的概念,应用场景等情况,并结合他们的特点及设计模式的原则进行分析。

1、工厂方法模式(Factory Method)

工厂方法模式分为三种:

11、普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图:

举例如下:(我们举一个发送邮件和短信的例子)

首先,创建二者的共同接口:
[java]view plaincopy publicinterfaceSender{publicvoidSend();}
其次,创建实现类:
[java]view plaincopy publicclassMailSenderimplementsSender{@OverridepublicvoidSend(){System.out.println("thisismailsender!");}} [java]view plaincopy publicclassSmsSenderimplementsSender{@OverridepublicvoidSend(){System.out.println("thisissmssender!");}}
最后,建工厂类:
[java]view plaincopy publicclassSendFactory{publicSenderproce(Stringtype){if("mail".equals(type)){returnnewMailSender();}elseif("sms".equals(type)){returnnewSmsSender();}else{System.out.println("请输入正确的类型!");returnnull;}}}
我们来测试下:
publicclassFactoryTest{publicstaticvoidmain(String[]args){SendFactoryfactory=newSendFactory();Sendersender=factory.proce("sms");sender.Send();}}
输出:this is sms sender!

22、多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图:

将上面的代码做下修改,改动下SendFactory类就行,如下:
[java]view plaincopypublicclassSendFactory{publicSenderproceMail(){ returnnewMailSender();}publicSenderproceSms(){returnnewSmsSender();}}
测试类如下:
[java]view plaincopy publicclassFactoryTest{publicstaticvoidmain(String[]args){SendFactoryfactory=newSendFactory();Sendersender=factory.proceMail();sender.Send();}}
输出:this is mailsender!

33、静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
[java]view plaincopy publicclassSendFactory{publicstaticSenderproceMail(){returnnewMailSender();}publicstaticSenderproceSms(){returnnewSmsSender();}} [java]view plaincopy publicclassFactoryTest{publicstaticvoidmain(String[]args){Sendersender=SendFactory.proceMail();sender.Send();}}
输出:this is mailsender!

总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。

2、抽象工厂模式(Abstract Factory)

工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。

请看例子:
[java]view plaincopy publicinterfaceSender{publicvoidSend();}
两个实现类:
[java]view plaincopy publicclassMailSenderimplementsSender{@OverridepublicvoidSend(){System.out.println("thisismailsender!");}} [java]view plaincopy publicclassSmsSenderimplementsSender{@OverridepublicvoidSend(){System.out.println("thisissmssender!");}}
两个工厂类:
[java]view plaincopy publicclassSendMailFactoryimplementsProvider{@OverridepublicSenderproce(){returnnewMailSender();}} [java]view plaincopy publicclassSendSmsFactoryimplementsProvider{@OverridepublicSenderproce(){returnnewSmsSender();}}
在提供一个接口:
[java]view plaincopy publicinterfaceProvider{publicSenderproce();}
测试类:
[java]view plaincopy publicclassTest{publicstaticvoidmain(String[]args){Providerprovider=newSendMailFactory();Sendersender=provider.proce();sender.Send();}}
其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!

3、单例模式(Singleton)

单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:

1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。

2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。

3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。

首先我们写一个简单的单例类:
[java]view plaincopy publicclassSingleton{/*持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载*/privatestaticSingletoninstance=null;/*私有构造方法,防止被实例化*/privateSingleton(){}/*静态工程方法,创建实例*/publicstaticSingletongetInstance(){if(instance==null){instance=newSingleton();}returninstance;}/*如果该对象被用于序列化,可以保证对象在序列化前后保持一致*/publicObjectreadResolve(){returninstance;}}
这个类可以满足基本要求,但是,像这样毫无线程安全保护的类,如果我们把它放入多线程的环境下,肯定就会出现问题了,如何解决?我们首先会想到对getInstance方法加synchronized关键字,如下:
[java]view plaincopy publicstaticsynchronizedSingletongetInstance(){if(instance==null){instance=newSingleton();}returninstance;}
但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进。我们改成下面这个:
[java]view plaincopy publicstaticSingletongetInstance(){if(instance==null){synchronized(instance){if(instance==null){instance=newSingleton();}}}returninstance;}
似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例:

a>A、B线程同时进入了第一个if判断

b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();

c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。

d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。

e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。

所以程序还是有可能发生错误,其实程序在运行过程是很复杂的,从这点我们就可以看出,尤其是在写多线程环境下的程序更有难度,有挑战性。我们对该程序做进一步优化:
[java]view plaincopy privatestaticclassSingletonFactory{privatestaticSingletoninstance=newSingleton();}publicstaticSingletongetInstance(){returnSingletonFactory.instance;}
实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这样我们暂时总结一个完美的单例模式:
[java]view plaincopy publicclassSingleton{/*私有构造方法,防止被实例化*/privateSingleton(){}/*此处使用一个内部类来维护单例*/privatestaticclassSingletonFactory{privatestaticSingletoninstance=newSingleton();}/*获取实例*/publicstaticSingletongetInstance(){returnSingletonFactory.instance;}/*如果该对象被用于序列化,可以保证对象在序列化前后保持一致*/publicObjectreadResolve(){returngetInstance();}}
其实说它完美,也不一定,如果在构造函数中抛出异常,实例将永远得不到创建,也会出错。所以说,十分完美的东西是没有的,我们只能根据实际情况,选择最适合自己应用场景的实现方法。也有人这样实现:因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字,也是可以的:
[java]view plaincopy publicclassSingletonTest{privatestaticSingletonTestinstance=null;privateSingletonTest(){}privatestaticsynchronizedvoidsyncInit(){if(instance==null){instance=newSingletonTest();}}publicstaticSingletonTestgetInstance(){if(instance==null){syncInit();}returninstance;}}
考虑性能的话,整个程序只需创建一次实例,所以性能也不会有什么影响。

补充:采用"影子实例"的办法为单例对象的属性同步更新
[java]view plaincopy publicclassSingletonTest{privatestaticSingletonTestinstance=null;privateVectorproperties=null;publicVectorgetProperties(){returnproperties;}privateSingletonTest(){}privatestaticsynchronizedvoidsyncInit(){if(instance==null){instance=newSingletonTest();}}publicstaticSingletonTestgetInstance(){if(instance==null){syncInit();}returninstance;}publicvoipdateProperties(){SingletonTestshadow=newSingletonTest();properties=shadow.getProperties();}}
通过单例模式的学习告诉我们:

1、单例模式理解起来简单,但是具体实现起来还是有一定的难度。

2、synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。

到这儿,单例模式基本已经讲完了,结尾处,笔者突然想到另一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同?

首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的)

其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。

再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。

最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题!

4、建造者模式(Builder)

工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。我们看一下代码:

还和前面一样,一个Sender接口,两个实现类MailSender和SmsSender。最后,建造者类如下: [java]view plaincopy publicclassBuilder{privateList list=newArrayList ();publicvoidproceMailSender(intcount){for(inti=0;i0){pos--;}returncollection.get(pos);}@OverridepublicObjectnext(){if(pos

Java开发中的23种设计模式详解(转)_Java开发模式

设计模式(Design Patterns)

——可复用面向对象软件的基础

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

一、设计模式的分类

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下:

二、设计模式的六大原则

1、开闭原则(Open Close Principle)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。

里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。

LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Bai 百科

3、依赖倒转原则(Dependence Inversion Principle)

这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle)

为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

原则是尽量使用合成/聚合的方式,而不是使用继承。

三、Java的23中设计模式

从这一块开始,我们详细介绍Java中23种设计模式的概念,应用场景等情况,并结合他们的特点及设计模式的原则进行分析。

1、工厂方法模式(Factory Method)

工厂方法模式分为三种:

11、普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图:

举例如下:(我们举一个发送邮件和短信的例子)

首先,创建二者的共同接口:
[java]view plaincopy publicinterfaceSender{publicvoidSend();}
其次,创建实现类:
[java]view plaincopy publicclassMailSenderimplementsSender{@OverridepublicvoidSend(){System.out.println("thisismailsender!");}} [java]view plaincopy publicclassSmsSenderimplementsSender{@OverridepublicvoidSend(){System.out.println("thisissmssender!");}}
最后,建工厂类:
[java]view plaincopy publicclassSendFactory{publicSenderproce(Stringtype){if("mail".equals(type)){returnnewMailSender();}elseif("sms".equals(type)){returnnewSmsSender();}else{System.out.println("请输入正确的类型!");returnnull;}}}
我们来测试下:
publicclassFactoryTest{publicstaticvoidmain(String[]args){SendFactoryfactory=newSendFactory();Sendersender=factory.proce("sms");sender.Send();}}
输出:this is sms sender!

22、多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图:

将上面的代码做下修改,改动下SendFactory类就行,如下:
[java]view plaincopypublicclassSendFactory{publicSenderproceMail(){ returnnewMailSender();}publicSenderproceSms(){returnnewSmsSender();}}
测试类如下:
[java]view plaincopy publicclassFactoryTest{publicstaticvoidmain(String[]args){SendFactoryfactory=newSendFactory();Sendersender=factory.proceMail();sender.Send();}}
输出:this is mailsender!

33、静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
[java]view plaincopy publicclassSendFactory{publicstaticSenderproceMail(){returnnewMailSender();}publicstaticSenderproceSms(){returnnewSmsSender();}} [java]view plaincopy publicclassFactoryTest{publicstaticvoidmain(String[]args){Sendersender=SendFactory.proceMail();sender.Send();}}
输出:this is mailsender!

总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。

2、抽象工厂模式(Abstract Factory)

工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。

请看例子:
[java]view plaincopy publicinterfaceSender{publicvoidSend();}
两个实现类:
[java]view plaincopy publicclassMailSenderimplementsSender{@OverridepublicvoidSend(){System.out.println("thisismailsender!");}} [java]view plaincopy publicclassSmsSenderimplementsSender{@OverridepublicvoidSend(){System.out.println("thisissmssender!");}}
两个工厂类:
[java]view plaincopy publicclassSendMailFactoryimplementsProvider{@OverridepublicSenderproce(){returnnewMailSender();}} [java]view plaincopy publicclassSendSmsFactoryimplementsProvider{@OverridepublicSenderproce(){returnnewSmsSender();}}
在提供一个接口:
[java]view plaincopy publicinterfaceProvider{publicSenderproce();}
测试类:
[java]view plaincopy publicclassTest{publicstaticvoidmain(String[]args){Providerprovider=newSendMailFactory();Sendersender=provider.proce();sender.Send();}}
其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!

3、单例模式(Singleton)

单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:

1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。

2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。

3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。

首先我们写一个简单的单例类:
[java]view plaincopy publicclassSingleton{/*持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载*/privatestaticSingletoninstance=null;/*私有构造方法,防止被实例化*/privateSingleton(){}/*静态工程方法,创建实例*/publicstaticSingletongetInstance(){if(instance==null){instance=newSingleton();}returninstance;}/*如果该对象被用于序列化,可以保证对象在序列化前后保持一致*/publicObjectreadResolve(){returninstance;}}
这个类可以满足基本要求,但是,像这样毫无线程安全保护的类,如果我们把它放入多线程的环境下,肯定就会出现问题了,如何解决?我们首先会想到对getInstance方法加synchronized关键字,如下:
[java]view plaincopy publicstaticsynchronizedSingletongetInstance(){if(instance==null){instance=newSingleton();}returninstance;}
但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进。我们改成下面这个:
[java]view plaincopy publicstaticSingletongetInstance(){if(instance==null){synchronized(instance){if(instance==null){instance=newSingleton();}}}returninstance;}
似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例:

a>A、B线程同时进入了第一个if判断

b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();

c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。

d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。

e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。

所以程序还是有可能发生错误,其实程序在运行过程是很复杂的,从这点我们就可以看出,尤其是在写多线程环境下的程序更有难度,有挑战性。我们对该程序做进一步优化:
[java]view plaincopy privatestaticclassSingletonFactory{privatestaticSingletoninstance=newSingleton();}publicstaticSingletongetInstance(){returnSingletonFactory.instance;}
实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这样我们暂时总结一个完美的单例模式:
[java]view plaincopy publicclassSingleton{/*私有构造方法,防止被实例化*/privateSingleton(){}/*此处使用一个内部类来维护单例*/privatestaticclassSingletonFactory{privatestaticSingletoninstance=newSingleton();}/*获取实例*/publicstaticSingletongetInstance(){returnSingletonFactory.instance;}/*如果该对象被用于序列化,可以保证对象在序列化前后保持一致*/publicObjectreadResolve(){returngetInstance();}}
其实说它完美,也不一定,如果在构造函数中抛出异常,实例将永远得不到创建,也会出错。所以说,十分完美的东西是没有的,我们只能根据实际情况,选择最适合自己应用场景的实现方法。也有人这样实现:因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字,也是可以的:
[java]view plaincopy publicclassSingletonTest{privatestaticSingletonTestinstance=null;privateSingletonTest(){}privatestaticsynchronizedvoidsyncInit(){if(instance==null){instance=newSingletonTest();}}publicstaticSingletonTestgetInstance(){if(instance==null){syncInit();}returninstance;}}
考虑性能的话,整个程序只需创建一次实例,所以性能也不会有什么影响。

补充:采用"影子实例"的办法为单例对象的属性同步更新
[java]view plaincopy publicclassSingletonTest{privatestaticSingletonTestinstance=null;privateVectorproperties=null;publicVectorgetProperties(){returnproperties;}privateSingletonTest(){}privatestaticsynchronizedvoidsyncInit(){if(instance==null){instance=newSingletonTest();}}publicstaticSingletonTestgetInstance(){if(instance==null){syncInit();}returninstance;}publicvoipdateProperties(){SingletonTestshadow=newSingletonTest();properties=shadow.getProperties();}}
通过单例模式的学习告诉我们:

1、单例模式理解起来简单,但是具体实现起来还是有一定的难度。

2、synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。

到这儿,单例模式基本已经讲完了,结尾处,笔者突然想到另一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同?

首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的)

其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。

再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。

最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题!

4、建造者模式(Builder)

工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。我们看一下代码:

还和前面一样,一个Sender接口,两个实现类MailSender和SmsSender。最后,建造者类如下: [java]view plaincopy publicclassBuilder{privateList list=newArrayList ();publicvoidproceMailSender(intcount){for(inti=0;i0){pos--;}returncollection.get(pos);}@OverridepublicObjectnext(){if(pos

java中几种常见的设计模式(java设计模式菜鸟教程)

1、工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。

2、建造模式:将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。

3、工厂方法模式:核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。

4、原始模型模式:通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。

5、单例模式:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。

6、适配器(变压器)模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。

7、桥梁模式:将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。

8、合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。

9、装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。

10、门面模式:外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。

11、享元模式:FLYWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态,它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来,将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象,而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。

12、代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。

13、责任链模式:在责任链模式中,很多对象由每一个对象对其下家的引用而接

起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。

14、命令模式:命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。

15、解释器模式:给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。在解释器模式中需要定义一个代表文法的命令类的等级结构,也就是一系列的组合规则。每一个命令对象都有一个解释方法,代表对命令对象的解释。命令对象的等级结构中的对象的任何排列组合都是一个语言。

16、迭代子模式:迭代子模式可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集,聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个独立的子对象中,从而与聚集本身隔开。迭代子模式简化了聚集的界面。每一个聚集对象都可以有一个或一个以上的迭代子对象,每一个迭代子的迭代状态可以是彼此独立的。迭代算法可以独立于聚集角色变化。

17、调停者模式:调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用。调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。

18、备忘录模式:备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。

19、观察者模式:观察者模式定义了一种一队多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。

20、状态模式:状态模式允许一个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一样。状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。

21、策略模式:策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模式把行为和环境分开。环境类负责维持和查询行为类,各种算法在具体的策略类中提供。由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。

22、模板方法模式:模板方法模式准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。

23、访问者模式:访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。访问者模式使得增加新的操作变的很容易,就是增加一个新的访问者类。访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。当使用访问者模式时,要将尽可能多的对象浏览逻辑放在访问者类中,而不是放到它的子类中。访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。

java中几种常见的设计模式(java设计模式菜鸟教程)

1、工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。

2、建造模式:将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。

3、工厂方法模式:核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。

4、原始模型模式:通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。

5、单例模式:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。

6、适配器(变压器)模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。

7、桥梁模式:将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。

8、合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。

9、装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。

10、门面模式:外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。

11、享元模式:FLYWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态,它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来,将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象,而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。

12、代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。

13、责任链模式:在责任链模式中,很多对象由每一个对象对其下家的引用而接

起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。

14、命令模式:命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。

15、解释器模式:给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。在解释器模式中需要定义一个代表文法的命令类的等级结构,也就是一系列的组合规则。每一个命令对象都有一个解释方法,代表对命令对象的解释。命令对象的等级结构中的对象的任何排列组合都是一个语言。

16、迭代子模式:迭代子模式可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集,聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个独立的子对象中,从而与聚集本身隔开。迭代子模式简化了聚集的界面。每一个聚集对象都可以有一个或一个以上的迭代子对象,每一个迭代子的迭代状态可以是彼此独立的。迭代算法可以独立于聚集角色变化。

17、调停者模式:调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用。调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。

18、备忘录模式:备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。

19、观察者模式:观察者模式定义了一种一队多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。

20、状态模式:状态模式允许一个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一样。状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。

21、策略模式:策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模式把行为和环境分开。环境类负责维持和查询行为类,各种算法在具体的策略类中提供。由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。

22、模板方法模式:模板方法模式准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。

23、访问者模式:访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。访问者模式使得增加新的操作变的很容易,就是增加一个新的访问者类。访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。当使用访问者模式时,要将尽可能多的对象浏览逻辑放在访问者类中,而不是放到它的子类中。访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。

《JavaScript设计模式》pdf下载在线阅读,求百度网盘云资源

《JavaScript设计模式》(Addy Osmani)电子书网盘下载免费在线阅读

链接:https://pan.baidu.com/s/1caEcDQAvAmUuo21WqI61wg

提取码:1234

书名:JavaScript设计模式

作者:Addy Osmani

译者:徐涛

豆瓣评分:6.9

出版社:人民邮电出版社

出版年份:2013-6-1

页数:241

内容简介:

《JavaScript设计模式》是JavaScript设计模式的学习指南。全书分为14章。首先介绍了什么是模式、模式的结构、类别、模式的分类、如何编写模式等等;然后,集中介绍了很多流行的设计模式在JavaScript中的应用,包括Mole(模块)模式、Observer(观察者)模式、Facade(外观)模式和Mediator(中介者)模式;最后,还探讨了模块化的JavaScript模式、jQuery及其插件中的设计模式。

作者简介:

addy osmani,谷歌chrome团队的开发项目工程师,对javascript应用程序架构有着强烈的爱好。他创建了比较流行的项目,如todomvc,并对modernizr和jquery等其他开源项目也做出很大贡献。作为一位高产的博主(http://addyosmani.com/blog),addy的文章经常出现在《javascript电子周刊》、《smashing杂志》及很多其他出版物上。

《JavaScript设计模式》pdf下载在线阅读,求百度网盘云资源

《JavaScript设计模式》(Addy Osmani)电子书网盘下载免费在线阅读

链接:https://pan.baidu.com/s/1caEcDQAvAmUuo21WqI61wg

提取码:1234

书名:JavaScript设计模式

作者:Addy Osmani

译者:徐涛

豆瓣评分:6.9

出版社:人民邮电出版社

出版年份:2013-6-1

页数:241

内容简介:

《JavaScript设计模式》是JavaScript设计模式的学习指南。全书分为14章。首先介绍了什么是模式、模式的结构、类别、模式的分类、如何编写模式等等;然后,集中介绍了很多流行的设计模式在JavaScript中的应用,包括Mole(模块)模式、Observer(观察者)模式、Facade(外观)模式和Mediator(中介者)模式;最后,还探讨了模块化的JavaScript模式、jQuery及其插件中的设计模式。

作者简介:

addy osmani,谷歌chrome团队的开发项目工程师,对javascript应用程序架构有着强烈的爱好。他创建了比较流行的项目,如todomvc,并对modernizr和jquery等其他开源项目也做出很大贡献。作为一位高产的博主(http://addyosmani.com/blog),addy的文章经常出现在《javascript电子周刊》、《smashing杂志》及很多其他出版物上。

软件设计模式主要有哪几种

软件设计模式主要有以下三大类共23种:

一、创建型模式:

1、工厂方法模式工厂方法模式的创建是因为简单工厂模式有一个问题,在简单工厂模式中类的创建依赖工厂类,如果想要拓展程序,必须对工厂类进行修改,这违背了开闭原则,所以就出现了工厂方法模式,只需要创建一个工厂接口和多个工厂实现类。

2、抽象工厂模式抽象工厂模式是提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。区别于工厂方法模式的地方,工厂方法模式是创建一个工厂,可以实现多种对象;而抽象工厂模式是提供一个抽象工厂接口,里面定义多种工厂,每个工厂可以生产多种对象。

3、单例模式单例模式能保证一个类仅有一个实例,并提供一个访问它的全局访问点,同时在类内部创造单一对象,通过设置权限,使类外部无法再创造对象。单例对象能保证在一个JVM中,该对象只有一个实例存在。

4、建造者模式建造者模式是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。在程序当中就是将一些不会变的基本组件,通过builder来进行组合,构建复杂对象,实现分离。

5、原型模式:原型模式是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。其实就是将对象复制了一份并返还给调用者,对象需继承Cloneable并重写clone方法。原型模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。

二、结构型模式:

1、适配器模式适配器模式是使得原本由于接口不兼容而不能一起工作的那些类可以一起工作,衔接两个不兼容、的接口的功能,使得它们能够一起工作,适配器起到中介的作用。

2、装饰模式:装饰器模式是动态地给一个对象添加一些额外的职责,给一个对象增加一些新的功能,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。除了动态的增加,也可以动态的撤销,要做到动态的形式,不可以用继承实现,因为继承是静态的。

3、代理模式代理模式是为其他对象提供一种代理以控制对这个对象的访问,也就是创建类的代理类,间接访问被代理类的过程中,对其功能加以控制。

4、外观模式外观模式是为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

5、桥接模式桥接模式是将抽象部分与实现部分分离,使它们都可以的变化。桥接模式就是把事物和其具体实现分开,使他们可以各自的变化(突然联想到了mvc模式)。

6、组合模式:组合模式是将对象组合成树形结构以表示"部分-整体"的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。

7、享元模式:享元模式是运用共享技术有效地支持大量细粒度的对象。享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,重用现有的同类对象,若未找到匹配的对象,则创建新对象,这样可以减少对象的创建,降低系统内存,提高效率。

三、行为型模式:

1、策略模式:

策略模式是定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换,且算法的变化不会影响到使用算法的客户。

2、模版方法模式:

模板方法模式是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。该模式就是在一个抽象类中,有一个主方法,再定义1...n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用。

模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤,将一些固定步骤、固定逻辑的方法封装成模板方法。调用模板方法即可完成那些特定的步骤。

3、观察者模式:

观察者模式是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

也就是当被观察者状态变化时,通知所有观察者,这种依赖方式具有双向性,在QQ邮箱中的邮件订阅和RSS订阅,当用户浏览一些博客时,经常会看到RSS图标,简单来说就是当订阅了该文章,如果后续有更新,会及时通知用户。这种现象即是典型的观察者模式。

4、迭代器模式:

迭代器模式是提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。

在Java当中,将聚合类中遍历各个元素的行为分离出来,封装成迭代器,让迭代器来处理遍历的任务;使简化聚合类,同时又不暴露聚合类的内部,在我们经常使用的JDK中各个类也都是这些基本的东西。

5、责任链模式:

责任链模式是避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。

6、命令模式:

命令模式是将一个请求封装成一个对象,从而使发出者可以用不同的请求对客户进行参数化。模式当中存在调用者、接收者、命令三个对象,实现请求和执行分开;调用者选择命令发布,命令指定接收者。

7、备忘录模式:

备忘录模式是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。创建一个备忘录类,用来存储原始类的信息;同时创建备忘录仓库类,用来存储备忘录类,主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,也就是做个备份。

8、状态模式:

状态模式是允许对象在内部状态发生改变时改变它的行为。对象具有多种状态,且每种状态具有特定的行为。

9、访问者模式:

访问者模式主要是将数据结构与数据操作分离。在被访问的类里面加一个对外提供接待访问者的接口,访问者封装了对被访问者结构的一些杂乱操作,解耦结构与算法,同时具有优秀的扩展性。通俗来讲就是一种分离对象数据结构与行为的方法。

10、中介者模式:

中介者模式是用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以地改变它们之间的交互。

11、解释器模式:

解释器模式是给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子,基本也就用在这个范围内,适用面较窄,例如:正则表达式的解释等。

扩展资料:

软件设计的概念以及意义:

软件设计模式是对软件设计经验的总结,是对软件设计中反复出现的设计问题的成功解决方案的描述。为了记录这些成功的设计经验并方便以后使用,软件设计模式通常包含 4 个基本要素:模式名称、问题、解决方案以及效果。

模式名称实际上就是一个帮助记忆的名称,是用于软件设计的技术术语,有助于设计者之间的交流。

问题描述了设计者所面临的设计场景,用于告诉设计者在什么情况下使用该模式。

解决方案描述了设计的细节,通常会给出方案的原理图示(例如 UML 的类图,序列图等,也可能是一些示意图)及相关文字说明,如果可能,还会给出一些代码实例,以便对解决方案的深入理解。

效果描述了设计方案的优势和劣势,这些效果通常面向软件的质量属性,例如,可扩展性、可复用性等。

软件设计模式的重要意义在于设计复用。设计模式可以使设计者更加方便地借鉴或直接使用已经过证实的成功设计方案,而不必花费时间进行重复设计。一些设计模式甚至提供了显示的类图设计及代码实例,为设计的文档化及软件的开发提供了直接的支持。

JS块级作用域和私有变量实例分析

每声明一个函数就会产生一个作用域。而外面的作用域访问不了里面的作用域(把里面的变量和函数隐藏起来),而里面的可以访问到外面的。对于隐藏变量和函数是一个非常有用的技术。

基于作用域隐藏的方法叫做最小授权或最小暴露原则。

这个原则是指在软件设计中,应该最小限度的暴露必要内容,而将其内容都隐藏起来,比如某个模块或对象得API设计。隐藏变量和函数可以解决同名标识符的之间的冲突,冲突会导致变量的意外覆盖。

例如:

var a = 2;function foo(){ var a = 3; console.log(a);}foo();console.log(a);

虽然这种技术可以解决一些问题,但是他并不理想,会导致一些额外的问题,首先必须声明一个具名函数foo(),意味着foo这个名称本身“污染”了所在的作用域,其次必须显式的通过函数名foo()调用这个函数才能运行其中的代码。

如果函数不需要函数名,并且能够自动运行,这会更加理想。幸好js提供了同时解决这两个问题的方案 -- (IIFE) Immediately Invoked Function Expression -- 立即执行函数

var a = 2;(function foo(){ var a = 3; console.log(a);})()console.log(a);

首先立即执行函数不会当做函数声明处理而是当做函数表达式处理。

区分函数声明还是函数表达式:看function在声明中是不是第一个词,如果是第一个词就是函数声明否则就是函数表达式。而立即执行函数" (function ",不是" function ",所以是函数表达式。

函数声明和函数表达式之间最重要的区别是他们的名称标识符将会绑定在何处

函数声明的函名称数会绑定在当前作用域内。假如在全局作用域创建一个函数声明,就可以在全局作用域访问这个函数名称并执行。而函数表达式的函数名称会绑定在自身的函数中,而不是当前说在作用域中。例如你全局创建一个函数表达式,如果你直接执行这个你创建的函数表达式的函数名就会报错,因为当前作用域下没有这个标识符,而你在函数表达式里面的作用域里访问这个函数名就会返回这个函数的引用。

作用域闭包,嗯,闭包这儿两个字就有点让人难以理解,(可以想象成一个包是关上的,里面隐藏了一些神秘的东西)而对于闭包的定义是这样说的:当函数可以记住并访问所在的作用域时,就产生了闭包,即使函数是在当前作用域之外执行。

for instance(拽个英文,哈哈)。

function foo() { var a = 2; function bar() { console.log(a); } bar();}foo();

上面的 代码bar()可以访问外部作用域中的变量。根据上面的定义这是闭包吗?从技术来讲也许是,但我们理解的是作用域在当前作用域查找变量如果没找到会继续向上面查找,找到返回,找不到继续找,直到全局作用域。-- 而这些正是闭包的一部分。函数bar()具有一个涵盖foo()作用域的闭包。

function foo(){ var a = 2; function bar (){ console.log(a); } return bar;}var baz = foo();baz();

在上面的代码更好的展示了闭包。

bar()函数在定义时作用域以外的地方执行(此时在全局作用域执行)。在foo()函数执行后,通常会期待foo()整个内部作用域都被销毁,因为我们知道引擎有垃圾回收器用来释放不在使用的内存空间,由于foo()已经执行完,看上去内容不会再被使用,所以很自然的会考虑对齐进行回收,回收后意味着里面的函数和变量访问不到了。foo()执行完,baz变量存着bar函数的引用。当执行baz也就是bar函数时。console.log(a)。不理解闭包的人可能认为会报错,事实上,打印的是2;???what?

foo()函数作用域不是执行完销毁了吗?怎么还能访问到a变量?-- 这就是闭包。

当foo()执行后,bar函数被返回全局作用域下,但是bar函数还保留着当时的词法作用域(当时写代码是的顺序就已经定义了作用域,这个作用域叫词法作用域--外面函数套着里面的函数的那种)甚至直到全局作用域。所以bar还留有foo()函数的引用。使得foo()函数没有被回收。

闭包可以说不出不在,只是你没有发现认出他。在定时器,事件监听器,ajax请求,跨窗口通信或者任何其他的异步(或者同步)任务中,只要使用了回调函数,实际上就是使用闭包。

for instance

function wait(message) { setTimeout(function timer() { console.log(message); }, 1000);}wait("hello");

在上面的代码中将一个内部函数(名为timer)传递给setTimerout(...).timer具有涵盖wait(...)的作用域的闭包。因此还保有对变量message的引用。wait()执行1000毫秒后,它的内部作用域不会消失,timer函数依然保有wait()作用域的闭包。

而闭包和立即执行函数息息相关。

循环和闭包

for(var i = 1; i <= 5; i++){ setTimeout(function timer(){ console.log(i); },i*1000);}

上面代码我们以为输出的会是1-5,可事实上输出的是5个6,这是为啥啊 -- 闭包啊。

延迟函数的回调会在循环结束时执行。事实上,当定时器运行时即使每个迭代的是setTimerout(...,0),所有的回调函数依然是循环结束后才会执行。我猜是跟js执行机制有关系吧。至于为什么都是6. 因为即使5个函数是在各个迭代中分别定义的,但是他们又被封闭在一个共享的全局作用域中因此实际上只有一个i.而怎么解决呢,立即执行函数来了!!!

for (var i = 1; i <= 5; i++) { (function (i) { setTimeout(function timer() { console.log(i); }, i * 1000); })(i)}

打印出来1,2,3,4,5了欧,这回是你想要的数了。解释一下,5次循环创建了5个立即执行函数,这5个函数的作用域都不相同,立即函数接收的参数是当前循环的i.所以当timer执行时访问的就是自己立即执行函数对应的作用域。也就是说5个timer函数分别对应5个作用域,每个作用域保存的变量i都不同,解决啦!!!

你懂闭包了吗?

js执行机制

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。JavaScript语言的设计者意识到这个问题,将所有任务分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。

哪些语句会放入异步任务队列及放入时机一般来说,有以下四种会放入异步任务队列:setTimeout 和 setlnterval ,DOM事件,ES6中的Promise,Ajax异步请求

本文来自 js教程 栏目,欢迎学习!

JS块级作用域和私有变量实例分析

每声明一个函数就会产生一个作用域。而外面的作用域访问不了里面的作用域(把里面的变量和函数隐藏起来),而里面的可以访问到外面的。对于隐藏变量和函数是一个非常有用的技术。

基于作用域隐藏的方法叫做最小授权或最小暴露原则。

这个原则是指在软件设计中,应该最小限度的暴露必要内容,而将其内容都隐藏起来,比如某个模块或对象得API设计。隐藏变量和函数可以解决同名标识符的之间的冲突,冲突会导致变量的意外覆盖。

例如:

var a = 2;function foo(){ var a = 3; console.log(a);}foo();console.log(a);

虽然这种技术可以解决一些问题,但是他并不理想,会导致一些额外的问题,首先必须声明一个具名函数foo(),意味着foo这个名称本身“污染”了所在的作用域,其次必须显式的通过函数名foo()调用这个函数才能运行其中的代码。

如果函数不需要函数名,并且能够自动运行,这会更加理想。幸好js提供了同时解决这两个问题的方案 -- (IIFE) Immediately Invoked Function Expression -- 立即执行函数

var a = 2;(function foo(){ var a = 3; console.log(a);})()console.log(a);

首先立即执行函数不会当做函数声明处理而是当做函数表达式处理。

区分函数声明还是函数表达式:看function在声明中是不是第一个词,如果是第一个词就是函数声明否则就是函数表达式。而立即执行函数" (function ",不是" function ",所以是函数表达式。

函数声明和函数表达式之间最重要的区别是他们的名称标识符将会绑定在何处

函数声明的函名称数会绑定在当前作用域内。假如在全局作用域创建一个函数声明,就可以在全局作用域访问这个函数名称并执行。而函数表达式的函数名称会绑定在自身的函数中,而不是当前说在作用域中。例如你全局创建一个函数表达式,如果你直接执行这个你创建的函数表达式的函数名就会报错,因为当前作用域下没有这个标识符,而你在函数表达式里面的作用域里访问这个函数名就会返回这个函数的引用。

作用域闭包,嗯,闭包这儿两个字就有点让人难以理解,(可以想象成一个包是关上的,里面隐藏了一些神秘的东西)而对于闭包的定义是这样说的:当函数可以记住并访问所在的作用域时,就产生了闭包,即使函数是在当前作用域之外执行。

for instance(拽个英文,哈哈)。

function foo() { var a = 2; function bar() { console.log(a); } bar();}foo();

上面的 代码bar()可以访问外部作用域中的变量。根据上面的定义这是闭包吗?从技术来讲也许是,但我们理解的是作用域在当前作用域查找变量如果没找到会继续向上面查找,找到返回,找不到继续找,直到全局作用域。-- 而这些正是闭包的一部分。函数bar()具有一个涵盖foo()作用域的闭包。

function foo(){ var a = 2; function bar (){ console.log(a); } return bar;}var baz = foo();baz();

在上面的代码更好的展示了闭包。

bar()函数在定义时作用域以外的地方执行(此时在全局作用域执行)。在foo()函数执行后,通常会期待foo()整个内部作用域都被销毁,因为我们知道引擎有垃圾回收器用来释放不在使用的内存空间,由于foo()已经执行完,看上去内容不会再被使用,所以很自然的会考虑对齐进行回收,回收后意味着里面的函数和变量访问不到了。foo()执行完,baz变量存着bar函数的引用。当执行baz也就是bar函数时。console.log(a)。不理解闭包的人可能认为会报错,事实上,打印的是2;???what?

foo()函数作用域不是执行完销毁了吗?怎么还能访问到a变量?-- 这就是闭包。

当foo()执行后,bar函数被返回全局作用域下,但是bar函数还保留着当时的词法作用域(当时写代码是的顺序就已经定义了作用域,这个作用域叫词法作用域--外面函数套着里面的函数的那种)甚至直到全局作用域。所以bar还留有foo()函数的引用。使得foo()函数没有被回收。

闭包可以说不出不在,只是你没有发现认出他。在定时器,事件监听器,ajax请求,跨窗口通信或者任何其他的异步(或者同步)任务中,只要使用了回调函数,实际上就是使用闭包。

for instance

function wait(message) { setTimeout(function timer() { console.log(message); }, 1000);}wait("hello");

在上面的代码中将一个内部函数(名为timer)传递给setTimerout(...).timer具有涵盖wait(...)的作用域的闭包。因此还保有对变量message的引用。wait()执行1000毫秒后,它的内部作用域不会消失,timer函数依然保有wait()作用域的闭包。

而闭包和立即执行函数息息相关。

循环和闭包

for(var i = 1; i <= 5; i++){ setTimeout(function timer(){ console.log(i); },i*1000);}

上面代码我们以为输出的会是1-5,可事实上输出的是5个6,这是为啥啊 -- 闭包啊。

延迟函数的回调会在循环结束时执行。事实上,当定时器运行时即使每个迭代的是setTimerout(...,0),所有的回调函数依然是循环结束后才会执行。我猜是跟js执行机制有关系吧。至于为什么都是6. 因为即使5个函数是在各个迭代中分别定义的,但是他们又被封闭在一个共享的全局作用域中因此实际上只有一个i.而怎么解决呢,立即执行函数来了!!!

for (var i = 1; i <= 5; i++) { (function (i) { setTimeout(function timer() { console.log(i); }, i * 1000); })(i)}

打印出来1,2,3,4,5了欧,这回是你想要的数了。解释一下,5次循环创建了5个立即执行函数,这5个函数的作用域都不相同,立即函数接收的参数是当前循环的i.所以当timer执行时访问的就是自己立即执行函数对应的作用域。也就是说5个timer函数分别对应5个作用域,每个作用域保存的变量i都不同,解决啦!!!

你懂闭包了吗?

js执行机制

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。JavaScript语言的设计者意识到这个问题,将所有任务分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。

哪些语句会放入异步任务队列及放入时机一般来说,有以下四种会放入异步任务队列:setTimeout 和 setlnterval ,DOM事件,ES6中的Promise,Ajax异步请求

本文来自 js教程 栏目,欢迎学习!

北大青鸟java培训:java的十种设计模式?

在java培训的过程中,我们需要了解到关于java的设计模式,下面是成都java培训http://www.kmbdqn.cn/介绍的关于java设计模式的相关介绍。

1、桥梁模式(Bridge):将抽象部分与它的实现部分分离,使它们都可以地变化。

2、合成模式(Composite):将对象组合成树形结构以表示"部分-整体"的层次结构。

它使得客户对单个对象和复合对象的使用具有一致性。

3、抽象工厂模式(AbstractFactory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

4、装饰模式(Decorator):动态地给一个对象添加一些额外的职责。

就扩展功能而言,它能生成子类的方式更为灵活。

5、适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口。

适配器模式使得原本由于接口或类不兼容而不能一起工作的类可以一起工作。

6、责任链模式(ChainofResponsibility):为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。

将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。

7、工厂方法(FactoryMethod):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。

FactoryMethod使一个类的实例化延迟到其子类。

8、建造模式(Builder):将一个复杂对象的构建与它的表示分离,使同样的构建过程可以创建不同的表示。

9、门面模式(Facade):为子系统中的一组接口提供一个一致的界面,门面模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

10、命令模式(Command):将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。

菲特宠物网还为您提供以下相关内容希望对您有帮助:

设计模式-生成器模式《六》

1、需要创建涉及各种部件的复杂对象。创建对象的算法应该独立于部件的装配方式。常见例子是构建组合对象 2、构建过程需要以不同的方式(例如,部件或表现的不同组合)构建对象 生成器模式: 构建复杂对象 以多个步骤构...

23种设计模式漫画版系列—生成器模式

生成器模式:漫画版设计模式探索 想象一下,造一辆汽车就像导演指挥一场复杂的舞台剧——生成器模式正扮演着这个角色。它将繁复的构造步骤分解为一个个独立的"生成器",每个负责特定部分,如车轮、内饰或手册的描述。这样,...

24种设计模式

2、生成器模式(Builder pattern): 使用生成器模式封装一个产品的构造过程, 并允许按步骤构造. 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示. 3、工厂模式(factory method pattern): ...

软件设计模式有哪些

生成器模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。工厂方法模式(FactoryMethord),定义一个用于创建对象的接口,让子类决定将哪一个类实例化。FactoryMethod使一个类的实例化...

软件设计模式主要有哪几种

3、单例模式单例模式能保证一个类仅有一个实例,并提供一个访问它的全局访问点,同时在类内部创造单一对象,通过设置权限,使类外部无法再创造对象。单例对象能保证在一个JVM中,该对象只有一个实例存在。 4、建造者模式建造者模式是将一...

JS常用设计模式(MVC、MVP、MVVM及其他设计模式)

一、MVC MVC模式的意思是,软件可以分成三个部分。视图(View):用户界面。控制器(Controller):业务逻辑 模型(Model):数据保存 各部分之间的通信方式如下。View 传送指令到 Controller Controller 完成业务逻辑后,要求 ...

设计模式(三)创建型模式

当一个类需要有多个实例存在时,不使用单例模式。从设计模式的本质上看,具体的例子和写法,可以参考菜鸟教程中的 建造者模式。建造者模式的典型使用场景是快餐店的套餐搭配模型。 套餐由若干个单个餐品组合而成。单个餐品又...

《JavaScript设计模式》pdf下载在线阅读,求百度网盘云资源

链接:https://pan.baidu.com/s/1caEcDQAvAmUuo21WqI61wg 提取码:1234 书名:JavaScript设计模式 作者:Addy Osmani 译者:徐涛 豆瓣评分:6.9 出版社:人民邮电出版社 出版年份:2013-6-1 页数:241 内容简介:《...

单件模式与生成器模式实验

策略模式帮助构建的对象不必自身包含逻辑,而是能够根据需要利用其它对象中的算法

设计模式都有哪些?

总体来说设计模式分为三大类: 一、创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 二、结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 三、行为...

Top