7199472950

7144063940状态模式及其结构

状态模式(State):当一个对象的内部状态发生改变时,会导致其行为的改变,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。当系统中某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。

模式的结构

UML

7017386-63f1dc902fd1195d

在状态模式结构图中包含如下几个角色:

  • Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。
  • State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
  • ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。

代码示例

当今社会,论坛贴吧很多,我们也会加入感兴趣的论坛,偶尔进行发言,但有时却会发现不能发帖了,原来是昨天的某个帖子引发了口水战,被举报了。这里就用论坛发帖为例,简单用代码描述一下:

7017386-b145d605557f8ca8

假设有三种状态,normal(正常),restricted(受限),closed(封号),判断依据是一个健康值(这里只是假设)。

pick-me-up2.1不用状态模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/* @Time    : 2018/8/10 下午3:16
**@Author : panda
**@Email : codepanda_li@163.com
**@File : account.go
**@Software: GoLand
*/
package account

import "fmt"

type AccountState int

const (
NORMAL AccountState = iota /正常0
RESTRICTED /受限
CLOSED /封号
)

type Account struct {
State AccountState
HealthValue int
}

func NewAccount(health int) *Account {
a := &Account{
HealthValue: health,
}
a.changeState()
return a
}

//看帖
func (a *Account) View() {
if a.State == NORMAL || a.State == RESTRICTED {
fmt.Println("正常看帖")
} else if a.State == CLOSED {
fmt.Println("账号被封,无法看帖")
}

}

//评论
func (a *Account) Comment() {
if a.State == NORMAL || a.State == RESTRICTED {
fmt.Println("正常评论")
} else if a.State == CLOSED {
fmt.Println("抱歉,你的健康值小于-10,不能评论")
}

}

//发帖
func (a *Account) Post() {
if a.State == NORMAL {
fmt.Println("正常发帖")
} else if a.State == RESTRICTED || a.State == CLOSED {
fmt.Println("抱歉,你的健康值小于0,不能发帖")
}
}

func (a *Account) changeState() {
if a.HealthValue <= -10 {
a.State = CLOSED
} else if a.HealthValue > -10 && a.HealthValue <= 0 {
a.State = RESTRICTED
} else if a.HealthValue > 0 {
a.State = NORMAL
}
}

//给账户设定健康值
func (a *Account) SetHealth(value int) {
a.HealthValue = value
a.changeState()
}

上面的代码很简单,能够实现需要的功能,但是却有几个问题:

  • 看帖和发帖方法中都包含状态判断语句,以判断在该状态下是否具有该方法以及在特定状态下该方法如何实现,导致代码非常冗长,可维护性较差;
  • 系统扩展性较差,如果需要增加一种新的状态,如hot状态(活跃用户,该状态用户发帖积分增加更多),需要对原有代码进行大量修改,扩展起来非常麻烦。

2.2使用状态模式

状态模式可以在一定程度上解决上述问题,在状态模式中将对象在每一个状态下的行为和状态转移语句封装在一个个状态类中,通过这些状态类来分散冗长的条件转移语句,让系统具有更好的灵活性和可扩展性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/* @Time    : 2018/8/10 下午3:37
**@Author : panda
**@Email : codepanda_li@163.com
**@File : account.go
**@Software: GoLand
*/
package saccount

import "fmt"

type Account struct {
State ActionState
HealthValue int
}
func NewAccount(health int) *Account {
a := &Account{
HealthValue: health,
}
a.changeState()
return a
}

func (a *Account)View() {
a.State.View()
}

func (a *Account)Comment() {
a.State.Comment()
}
func (a *Account)Post() {
a.State.Post()
}
type ActionState interface {
View()
Comment()
Post()
}

type CloseState struct {

}

func (c *CloseState)View() {
fmt.Println("账号被封,无法看帖")
}

func (c *CloseState)Comment() {
fmt.Println("抱歉,你的健康值小于-10,不能评论")
}
func (c *CloseState)Post() {
fmt.Println("抱歉,你的健康值小于0,不能发帖")
}

type RestrictedState struct {

}
func (r *RestrictedState)View() {
fmt.Println("正常看帖")
}

func (r *RestrictedState)Comment() {
fmt.Println("正常评论")
}
func (r *RestrictedState)Post() {
fmt.Println("抱歉,你的健康值小于0,不能发帖")
}

type NormalState struct {

}
func (n *NormalState)View() {
fmt.Println("正常看帖")
}

func (n *NormalState)Comment() {
fmt.Println("正常评论")
}
func (n *NormalState)Post() {
fmt.Println("正常发帖")
}
func (a *Account) changeState() {
if a.HealthValue <= -10 {
a.State = &CloseState{}
} else if a.HealthValue > -10 && a.HealthValue <= 0 {
a.State = &RestrictedState{}
} else if a.HealthValue > 0 {
a.State = &NormalState{}
}
}

//给账户设定健康值
func (a *Account) SetHealth(value int) {
a.HealthValue = value
a.changeState()
}

优点和缺点

优点

状态模式的主要优点如下:

  • 封装了状态的转换规则,在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。
  • 将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。
  • 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,状态模式可以避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起。
  • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

gas缺点

状态模式的主要缺点如下:

  • 状态模式的使用必然会增加系统中类和对象的个数,导致系统运行开销增大。
  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,增加系统设计的难度。
  • 状态模式对“开闭原则”的支持并不太好,增加新的状态类需要修改那些负责状态转换的源代码,否则无法转换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

适用环境

在以下情况下可以使用状态模式:

  • 对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为。
  • 代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。

模式应用

状态模式在工作流或游戏等类型的软件中得以广泛使用,甚至可以用于这些系统的核心功能设计,如在政府OA办公系统中,一个批文的状态有多种:尚未办理;正在办理;正在批示;正在审核;已经完成等各种状态,而且批文状态不同时对批文的操作也有所差异。使用状态模式可以描述工作流对象(如批文)的状态转换以及不同状态下它所具有的行为。

观察者模式

443-966-2644定义

8434847788观察者模式在软件设计中是一个对象,维护一个依赖列表,当任何状态发生改变自动通知它们。

(844) 386-9688观察者模式定义了一系列对象之间的一对多关系。

当一个对象改变状态,其他依赖者都会收到通知

image

/www.runoob.com/design-pattern/observer-pattern.html #菜鸟教程

优点:

  • 1、观察者和被观察者是抽象耦合的。
  • 2、建立一套触发机制。

缺点:

  • 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
  • 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
  • 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

代码 通过watchdog 监控文件夹变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#coding:utf-8
import watchdog
from watchdog.observers import Observer
from watchdog.events import *
import time

class FileEventHandler(FileSystemEventHandler):
def __init__(self):
FileSystemEventHandler.__init__(self)

def on_moved(self, event):
if event.is_directory:
print("directory moved from {0} to {1}".format(event.src_path,event.dest_path))
else:
print("file moved from {0} to {1}".format(event.src_path,event.dest_path))

def on_created(self, event):
if event.is_directory:
print("directory created:{0}".format(event.src_path))
else:
print("file created:{0}".format(event.src_path))

def on_deleted(self, event):
if event.is_directory:
print("directory deleted:{0}".format(event.src_path))
else:
print("file deleted:{0}".format(event.src_path))

def on_modified(self, event):
if event.is_directory:
print("directory modified:{0}".format(event.src_path))
else:
print("file modified:{0}".format(event.src_path))

if __name__ == "__main__":
observer = Observer()
event_handler = FileEventHandler()
observer.schedule(event_handler,r"G:\新建文件夹",True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()

8053137444问题

公司人员的入职,it的提供的哪些系统或者服务要同步更新?

1.新建AD账户
2.新建邮箱
3.加入无线权限
4.加入对应的组和OU
5.发送AD密码给同事
…

离职?

发布-订阅设计模式(Publisher)(Subscriber)

转载 /www.jianshu.com/p/3098b1176357

介绍

用一个全局对象,负责模块间的通信,具体落实发布和订阅两种功能。发布者不需要知道订阅者,订阅者不需要知道发布者,发布者能启动功能器使订阅者收到消息,这就足够了

(902) 253-1728优势

1、统一管理

订阅模式中,可以抽离出调度中心单独成一个文件,可以对一系列的订阅事件进行统一管理。

(906) 886-53872、松耦合

发布者不需要知道订阅者的数量,订阅者听得话题或者订阅者是通过什么方式运行的。他们能够相互独立地运行,这样就可以让你分开开发这两部分而不需要担心对状态或实现的任何细微的影响。

302-327-6083缺点

1、状态未知

发布者不知道订阅者的状态,反之亦然,这样的话,你根本不知道在另一端是否会没有问题?

(780) 995-81532、不能识别恶意消息

攻击者(恶意的发布者)能够入侵系统并且撕开它。这会导致恶意的消息被发布,订阅者能够获得他们以前并不能获得的消息。

97239290043、关系更新难

更新发布者和订阅者的关系会是一个很难的问题,因为毕竟他们根本不认识对方。

620-893-1286看代码 ZeroMQ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'''
服务端,发布模式
@author:
'''
import time
import zmq
from random import randrange

context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp:/*:5566")

while True:
zipcode = randrange(1, 100000)
time.sleep(1)
print({"as":zipcode})
socket.send_json({"as":zipcode})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
'''
订阅模式,如果设置了过滤条件,那么只会接收到以过滤条件开头的消息
'''
import sys
import zmq

# Socket to talk to server
context = zmq.Context()
socket = context.socket(zmq.SUB)

print("Collecting updates from weather server...")
socket.connect("tcp:/localhost:5566")



socket.setsockopt_string(zmq.SUBSCRIBE, '')

total_temp = 0
while True:
string = socket.recv_json()
#zipcode, temperature, relhumidity = string.split()
print(type(string),string)

再举个荔枝,

我来公司面试的时候,完事之后每个面试官都会对我说:“请留下你的联系方式, 有消息我们会通知你”。 在这里“我”是订阅者, 面试官是发布者。所以我不用每天或者每小时都去询问面试结果, 通讯的主动权掌握在了面试官手上。而我只需要提供一个联系方式。

这个是什么模式??

观察者模式(Observer) 和 发布-订阅设计模式(Publisher)(Subscriber)区别

image

(434) 284-1544差异快速总结

在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。

在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。

观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)。

观察者模式需要在单个应用程序地址空间中实现,而发布-订阅更像交叉应用模式。

装饰器模式

5745817336装饰器模式

什么是装饰器模式?

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

装饰器模式的目的?

动态地给一个对象添加一些额外的职责 。

在不想增加很多子类的情况下扩展类 。

示例1

我们简单的理解装饰器,可以认为它是一种包装,对对象,方法,熟悉的包装。当我们需要访问一个对象的时候,如果我们通过这个对象外围的包装去访问的话,被这个包装附加的行为就会被触发。例如 一把加了消声器的枪。消声器就是一个装饰,但是它和原来的枪成为一个整体,开枪的时候消声器就会发生作用 。

孙悟空有 72 变,当他变成”庙宇”后,他的根本还是一只猴子,但是他又有了庙宇的功能。

装饰模式场景 —— 面向 AOP 编程

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是8226521441的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的708-379-5784降低,提高程序的可重用性,同时提高了开发的效率。(百度百科)

JavaScript装饰器模式的实现:

以钢铁侠为例,钢铁侠本质是一个人,只是“装饰”了很多武器方才变得那么 NB,不过再怎么装饰他还是一个人。

我们的示例场景是这样的

  • 首先创建一个普通的Man类,它的抵御值 2,攻击力为 3,血量为 3;

  • 然后我们让其带上钢铁侠的盔甲,这样他的抵御力增加 100,变成 102;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    / 首先我们要创建一个基类
    function Man(){

    this.def = 2;
    this.atk = 3;
    this.hp = 3;
    }

    / 装饰者也需要实现这些方法,遵守 Man 的接口
    Man.prototype={
    toString:function(){
    return `防御力:${this.def},攻击力:${this.atk},血量:${this.hp}`;
    }
    }
    / 创建装饰器,接收 Man 对象作为参数。
    var Decorator = function(man){
    this.man = man;
    }

    / 装饰者要实现这些相同的方法
    Decorator.prototype.toString = function(){
    return this.man.toString();
    }

    / 继承自装饰器对象
    / 创建具体的装饰器,也是接收 Man 作对参数
    var DecorateArmour = function(man){

    var moreDef = 100;
    man.def += moreDef;
    Decorator.call(this,man);

    }
    DecorateArmour.prototype = new Decorator();

    / 接下来我们要为每一个功能创建一个装饰者对象,重写父级方法,添加我们想要的功能。
    DecorateArmour.prototype.toString = function(){
    return this.man.toString();
    }

    / 注意这里的调用方式
    / 构造器相当于“过滤器”,面向切面的
    var tony = new Man();
    tony = new DecorateArmour(tony);
    console.log(`当前状态 ===> ${tony}`);
    / 输出:当前状态 ===> 防御力:102,攻击力:3,血量:3

与Java做对比:

和Java等语言不同的是,Java的装饰器模式是给对象动态添加职责,JavaScript中,给对象添加职责的能力是与生俱来的,更侧重于给函数动态添加职责。

与python做对比:

由于JavaScript缺少类的特性,继承对于它来说就显得有点鸡肋了,在python中,有更加简单的添加装饰器的方法,直接通过”@”给函数自动添加装饰器,达到扩展功能的目的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def api_auth(func):
def wrapper(request):
timestamp = request.GET.get('timestamp', None)
nonce = request.GET.get('nonce', None)
signature = request.GET.get('signature', None)
clientid = request.GET.get('clientid', None)
securty_key = {'timestamp': timestamp,'nonce': nonce,'signature': signature,'clientid':clientid}
if not securty_key:
return HttpResponse('Unauthorized')
if not Securty.auth_api_vaild(securty_key):
return HttpResponse('Unauthorized')
return func(request)
return wrapper

@api_auth
def current_wireless_permisson(request):
result={}
jobnumber = request.GET.get('jobnumber', None)
username = showadaccount(jobnumber)['adaccount']
if username:
wireless_permisson = IsExistAdGroupByUser(username,'WifiUsers')['isSuccess']
if wireless_permisson:
result['permisson'] = '1'
else:
result['permisson'] = '0'
else:
result['permisson'] = '0'
response = HttpResponse(JsonResponse(result), content_type="application/json;charset=utf-8")
return response

不过装饰器是 ES7(也就是ES2016)的提案,虽然听着感觉好像还有点遥远,毕竟 ES6 还没有走多久呢,但实际上,2016年已经到来,也就是说,ES7 的提案今年就会成为新的标准

接着上面那个例子,我们用ES7怎么来写呢?

Babel

创建 Man 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Man{
constructor(def = 2,atk = 3,hp = 3){
this.init(def,atk,hp);
}

init(def,atk,hp){
this.def = def; / 防御值
this.atk = atk; / 攻击力
this.hp = hp; / 血量
}
toString(){
return `防御力:${this.def},攻击力:${this.atk},血量:${this.hp}`;
}
}

var tony = new Man();

console.log(`当前状态 ===> ${tony}`);

/ 输出:当前状态 ===> 防御力:2,攻击力:3,血量:3

创建 decorateArmour 方法,为钢铁侠装配盔甲——注意 decorateArmour 是装饰在方法init上的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function decorateArmour(target, key, descriptor) {
const method = descriptor.value;
let moreDef = 100;
let ret;
descriptor.value = (...args)=>{
args[0] += moreDef;
ret = method.apply(target, args);
return ret;
}
return descriptor;
}

class Man{
constructor(def = 2,atk = 3,hp = 3){
this.init(def,atk,hp);
}

@decorateArmour
init(def,atk,hp){
this.def = def; / 防御值
this.atk = atk; / 攻击力
this.hp = hp; / 血量
}
toString(){
return `防御力:${this.def},攻击力:${this.atk},血量:${this.hp}`;
}
}

var tony = new Man();

console.log(`当前状态 ===> ${tony}`);
/ 输出:当前状态 ===> 防御力:102,攻击力:3,血量:3

日志装饰器

装饰器一种很方便的用法就是快速为方法添加记录日志的行为。下面这个例子中,我们实现了一个日志装饰器,函数被调用时会记录函数名。这个装饰器也可以自定义日志消息。请注意,如果我们要为装饰器提供参数,我们需要返回一个函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function log(target, name, descriptor) {
let message = `LOG: Calling \`${name}\` function.`;

if (typeof target === 'string') {
message = target;

return (target, name, descriptor) => {
console.log(`LOG: ${message}`, name);
return descriptor;
};
} else {
console.log(message);
return descriptor;
}
}

class Robot {
@log
destroyHumans() {
return `Destroying humans.`;
}
}

const robot = new Robot();
console.log(robot.destroyHumans());
/ LOG: Calling `destroyHumans` function.
/ "Destroying humans."

优缺点

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂。

(713) 340-2356

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元(flyweight)模式是一种用于性能优化的模式,“fly”在这里是苍蝇的意思,意为蝇量级。享元模式的核心是运用共享技术来有效支持大量细粒度的对象。

假设有个内衣工厂,目前的产品有50种男式内衣和50种女士内衣,为了推销产品,工厂决定生产一些塑料模特来穿上他们的内衣拍成广告照片。正常情况下需要50个男模特和50个女模特,然后让他们每人分别穿上一件内衣来拍照。不使用享元模式的情况下,在程序里也许会这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var Model = function(sex, underwear) {
this.sex = sex;
this.underwear= underwear;
};
Model.prototype.takePhoto = function() {
console.log('sex= ' + this.sex + ' underwear=' + this.underwear);
};
for ( var i = 1; i <= 50; i++ ) {
var maleModel = new Model('male', 'underwear' + i );
maleModel.takePhoto();
};
for ( var j = 1; j <= 50; j++ ) {
var femaleModel= new Model('female', 'underwear' + j );
femaleModel.takePhoto();
};

 要得到一张照片,每次都需要传入sex和underwear参数,如上所述,现在一共有50种男内衣和50种女内衣,所以一共会产生100个对象。如果将来生产了10000种内衣,那这个程序可能会因为存在如此多的对象已经提前崩溃

  下面来考虑一下如何优化这个场景。虽然有100种内衣,但很显然并不需要50个男模特和50个女模特。其实男模特和女模特各自有一个就足够了,他们可以分别穿上不同的内衣来拍照

  现在来改写一下代码,既然只需要区别男女模特,那先把underwear参数从构造函数中移除,构造函数只接收sex参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var Model = function(sex) {
this.sex = sex;
};
Model.prototype.takePhoto = function() {
console.log('sex= ' + this.sex + ' underwear=' + this.underwear);
};
/分别创建一个男模特对象和一个女模特对象
var maleModel = new Model('male'),
var femaleModel = new Model('female');

/给男模特依次穿上所有的男装,并进行拍照
for (var i = 1; i <= 50; i++ ) {
maleModel.underwear = 'underwear' + i;
maleModel.takePhoto();
};
/给女模特依次穿上所有的女装,并进行拍照
for (var j = 1; j <= 50; j++ ) {
femaleModel.underwear = 'underwear' + j;
femaleModel.takePhoto();
};

​ Flyweight中有两个重要概念–内部状态intrinsic和外部状态extrinsic之分,内部状态就是在对象里通过内部方法管理,而外部信息可以在通过外部删除或者保存。

​ 说白点,就是先捏一个的原始模型,然后随着不同场合和环境,再产生各具特征的具体模型,很显然,在这里需要产生不同的新对象,所以Flyweight模式中常出现Factory模式,Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个Flyweight pool(对象池)来存放内部状态的对象。

​ 对象池维护一个装载空闲对象的池子,如果需要对象的时候,不是直接new,而是转从对象池里获取。如果对象池里没有空闲对象,则创建一个新的对象,当获取出的对象完成它的职责之后,再进入池子等待被下次获取

  对象池的原理很好理解,比如我们组人手一本《JavaScript权威指南》,从节约的角度来讲,这并不是很划算,因为大部分时间这些书都被闲置在各自的书架上,所以我们一开始就只买一本,或者一起建立一个小型图书馆(对象池),需要看书的时候就从图书馆里借,看完了之后再把书还回图书馆。如果同时有三个人要看这本书,而现在图书馆里只有两本,那我们再马上去书店买一本放入图书

享元模式是一种很好的性能优化方案,但它也会带来一些复杂性的问题,从前面两组代码的比较可以看到,使用了享元模式之后,需要分别多维护一个factory对象和一个manager对象,在大部分不必要使用享元模式的环境下,这些开销是可以避免的

  享元模式带来的好处很大程度上取决于如何使用以及何时使用,一般来说,以下情况发生时便可以使用享元模式

  1、一个程序中使用了大量的相似对象

  2、由于使用了大量对象,造成很大的内存开销

  3、对象的大多数状态都可以变为外部状态

  4、剥离出对象的外部状态之后,可以用相对较少的共享对象取代大量对象。

优点:大大减少对象的创建,降低系统的内存,使效率提高。

缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱

9203205322

WebRTC的学习资料


trigoneutismWebRTC的国内学习资料

入门系列(by (979) 608-8497)


深入篇(by 博客园:RTC.Blacker)
webrtc系列


关于屏幕共享的一些资料

  • 920-284-5114
    这个是一个基于Electron的屏幕共享,但是目前我还未能将demo跑通。
  • 219-302-9262 这个是Electron原生的一个模块,我看了screencat的源码也有这一相关的内容,而且网上也有网友是基于这个已经实现了image
  • (231) 942-5578 这个在mk大神的实验中已经可以实现,是基于chrome的插件

基于webrtc的一些商业产品

Slack:Where work happens

什么是Slack

Slack 是聊天群组 + 大规模工具集成 + 文件整合 + 统一搜索。 415-455-4140
image


734-330-6890Slack优点

  1. 方便的channel
  2. 无干扰的通知
  3. 超低的沟通成本
  4. 强大的第三方集成
  5. 折腾

Slack的缺点

  1. 定制功能
  2. 国外的服务器,可能被墙
  3. 付费
  4. 水土不服

sorrow-laden一些可替代的开源产品

scorpionwortMattermost

Mattermost提供群聊、直接通讯和私人聊天室。功能包括全记录支持、文件上传、存档和搜索,以及个性化主题,甚至允许用户从Slack导入聊天记录和喜爱的主题。Mattermost提供了多种Slack没有的功能,包括根据标签搜索、为多语言团队提供非英语渠道名称、自动突出你的发言以及留言线程以便追踪对话。

技术:

  • 后端使用高性能Go语言
  • 前端采用React
  • 支持MySQL和PostgreSQL

(480) 930-6196920-779-6361

Rocket.Chat是一款功能最丰富的开源Slack替代,具有群聊、直接通讯、私聊室、桌面通知、媒体嵌入、链接预览、文件上传、语音/视频聊天、界面共享等等。有适用Windows,MAC,和Linux的本地应用程序,以及适用于iOS和Android的移动应用程序。火箭。Rocket.Chat也有Sandstorm应用程序,所以你可以很容易地自主托管服务器。开发人员可以使用hubot与主流服务如GitHub,Gitlab,Confluence,JIRA等进行集成。即将推出的新功能包括OTR通讯,XMPP多用户聊天,Kerberos身份验证,通过P2P和可扩展多播工具共享文件,等等。

技术:

  • 使用Meteor平台,包括前端Blaze
  • 代码综合使用CoffeeScript和JavaScript
  • MongoDB

Zulip

Zulip原本是一个独立的应用,但Dropbox公司在Zulip正式推出前就收购了打造它的公司。该应用程序现在是一个开源项目。Zulip功能包括群聊、直接通讯、私人组、线程会话、在线媒体预览、电子邮件和桌面通知以及许多集成功能。除了浏览器版本,Zulip也有本地桌面和适用于iOS,Android,Linux,MAC和Windows的移动应用,所以你几乎可以在任何平台上聊天。

技术:

  • 用Python写的服务器(Twisted+ Django)
  • 前端似乎使用JavaScript + jQuery
  • PostgreSQL,Memcached,Redis,RabbitMQ

5144881049国内的一些类似产品

BearyChat

中文名「倍洽」,是一款面向企业和团队的沟通工具,即时沟通为基础,通过 「第三方服务集成」、「文件共享」、「自定义机器人」等方式将用户关心的信息实时汇聚起来,再通过信息的「永久保存」、「一键收藏」、「全局搜索」、「实时预览」帮用户将信息流快速梳理,从而提高工作效率

技术:

  • 前端是AngularJS+LESS
  • 后端的话主要是Erlang

优点:

  • chatops
    image
  • 国内的产品
  • 公司集成的插件很好

缺点:

  • 收费
  • 暂时还没有API开放
  • 还没有开源

513-614-7892简聊

是一款免费的企业级即时沟通工具,是平行于团队协作工具 Teambition 的另一款能够改善员工工作效率的产品。「简聊」打通了企业内沟通、任务、人员、文件等各种要素和流程,并通过「分话题、有目标」的企业级即时聊天模式,来让团队沟通变得更有效率。

技术:

  • 数据库MongoDB
  • Redis缓存和消息通讯中间件
  • 搜索使用的是ElasticSearch 1.6.2 + ik 中文分词插件
  • 使用nodejs

优点:

  • 开源
  • 专注Teambition
  • 自己定制

缺点:

  • 开源代码已经不更新了
  • 可恶的PhantomJS