0%

设计模式分类

创建型:

  1. factory method:工厂类接口,在工厂类实现中定义要创建的类。==典型特征:只有一个创建方法。==
  2. abstract factory:工厂类接口,在工厂类实现中定义要创建的一类产品族。==典型特征:有多个创建不同产品的方法。==
  3. builder:通过部件,组装产品。在建造者中,依次添加产品部件。==典型特征:建造类中添加组件,产品类中有个执行方法。==
  4. prototype:clone模式,通过克隆创建新对象。==典型特征:实现Clonable,有浅克隆、深克隆==
  5. singleton:单例模式,饿汉式/懒汉式(同步方法,嵌套【同步代码块+双重检测】,volatile+双重检测)。==典型特征:饿汉式较安全,懒汉式可以提高系统初始化速度,但要注意多线程安全==

结构型:

  1. adapter:API转换,封装具体的实现类,提供统一接口。==典型特征:有一套标准的接口API,其他实现类,需要经过适配器封装成标准API模式。==
  2. bridge:桥接模式,类似静态代理。==典型特征:定义功能接口。具体类delegate功能类,完成其部分功能。==
  3. composite:复合模式,将对象组合成树形结构,表示“整体-部分”的层次结构,使得对单个对象和复合对象的调用一致。==典型特征:树、子树、树叶,树叶屏蔽部分方法。==
  4. decorator:装饰器模式,动态的为具体类添加功能。==典型特征:装饰器抽象类实现目标接口类,然后装饰器具体类delegate具体对象。==
  5. facade:外观模式,隐藏内部实现方式,定义统一的接口,方便外部调用。==典型特征:给外部定义专用的接口,对内部具体实现类封装。==
  6. flyWeight:享元模式,是一个提高程序效率和性能的模式,采用共享来避免大量拥有相同内容对象的开销。==典型特征:结合工厂模式,传入key,目标对象已存在,直接返回;不存在,创建后返回。==
  7. proxy:代理模式,为其他对象提供一个代理类,控制访问。==典型特征:实现jdk动态代理,或者cglib动态代理接口。在方法调用前后,控制访问。==

行为型:

  1. observer:观察者模式,也称publish-subscribe模式。jdk自带接口类java.util.Observable实现发布者;java.util.Observer实现订阅者。
  2. state:使得对象被划分成对象 + 状态对象两部分,一定程度上体现了Delegate的设计原则。替代if…else/switch的一种方式 。状态以类表示,包含对应状态的执行动作。每次执行后,切换状态。
  3. strategy:策略模式,一个行为有多种实现。根据调用者动态选择不同行为实现。
  4. visitor:访问者模式,由访问者,对象结构类,元素接口,元素类构成。由对象结构类组装访问者+元素,易拓展,但是零散/复杂。
  5. interpreter:解释器模式,给定一个语言,定义它的的文法的一种表示,并定义一个解释器。解释器使用该表示来解释语言中的句子。
  6. template method:模板方法模式,接口中定义骨架,具体实现延迟到子类。
  7. chain of responsibility:责任链模式,将请求的发送者/接收者解耦合,使多个接收对象都有机会处理请求。将这些对象连成一条链(线,树,环),沿着链传递请求,直到有一个对象处理它。
  8. command:命令行模式,将请求封装成一个对象,从而可以使用不同的请求命令对客户(invoker)进行参数化;对请求排队或记录日志,以及支持可取消的操作。缺点:会导致某些系统有过多的具体Command类。
  9. iterator:迭代器模式,提供一个方法,顺序访问一个聚合对象的各个元素,而又不暴露该对象的内部表示。常见实现接口java.util.Iterator,提供不同实现,高效迭代聚合对象(因为底层数据结构不同)。
  10. mediator:中介者模式,用一个中介者对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立的改变他们之间的交互。==典型特征:同事类注册给终结者。同事类调用时,由中介者协调其他注册的同事类行为。==
  11. memento:备忘录模式,在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存前的状态。

参考文档:

  1. http://blog.csdn.net/zhoudaxia/article/details/17048853

问题:输入整数对‘p q’,如果不存在其他整数与p、q相连或者相连的整数不能连接到对方,则将p、q直接相连;否则认为p、q相连,不操作。

建立问题模型

对象关系:

  • 自反性:p与自身相连
  • 对称性:若p与q相连,则q与p也相连
  • 传递性:若p与q相连,q与r相连,则p与r相连

基本操作:

  • find:查询触点所在连通分量
  • union:合并两个连通分量

API设计:

1
2
3
4
5
6
7
8
9
10
11
public class UF {
//ids存放触点,count对分量计数
int[] ids;
int count;

UF(int N); //initialize data structure
int find(int p); //查询所在分量
boolean connected(int p,int q); //are p and q in the same component?
void union(int p,int q); //add connection between p and q
int count(); //number of components
}

算法实现及演变

1.quick-find

用数组索引表示原始对象,对应值表示所属分量。

查询快;

合并慢,每次都修改被合并分量中所有触点。

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
public class UF{
int[] ids;
int count;

public UF(int N){
ids = new int[N];
for(int i=0; i<N; i++){
ids[i] = i;
}
count = N;
}

public int find(int p){
return ids[p];
}

public boolean connected(int p,int q){
return ids[p] == ids[q];
}

public void union(int p,int q){
int pId = ids[p];
int qId = ids[q];

if(pId != qId){
for(int i=0; i<ids.length(); i++){
if(qid == ids[i]){
ids[i] = pId;
}
count++;
}
}else{
return;
}
}
}

复杂度:以数组访问次数计算

  • find:1
  • union:被合并分量只有一个触点时,2+N+1 = N+3;被合并分量有N-1个触点时,2+N+(N-1) = 2N+1。即,N+3 ~ 2N+1。
  • 需要N-1次操作,那么,至少需要(N-1)(N+3) ~ N^2^ 次数的数组访问。
  • 得,quick-union算法是平方级别的。

2.quick-union

用数组索引表示原始对象,对应值链接到所属分量(分量内,各触点使用通过值对应到另一个的索引连接–形成链)

==加快union;==

减慢find,要遍历当前触点到所属分量根触点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public int find(int p){
while(p != ids[p]){
p = ids[p] //复杂度增加
}
return p;
}

public void union(int p,int q){
int pRoot = find(p);
int qRoot = find(q);
if(pRoot == qRoot) return; //复杂度降低
ids[pRoot] = qRoot;
count--;
}

复杂度:以数组访问次数计算

  • find:最少1次,最多2*(N-1)+1=2N+1
  • union:2*(2N+1) ~ N;极端情况下,输入(0,1),(0,2)…… 2(1+2+3+…+N) ~ N^2^
  • 复杂度受输入影响较大

3.weighted quick-union

以两个数组表示,一个存储原始对象及所属链;另一个存储链的大小。

促使长度小的链,链接到长度大的链上。降低了树的高度,==解决了quick-union中极端情况下复杂度大的问题。==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private int[] ids;
private int[] sz;

private int find(int p){
while(p != ids[p]){
p = ids[p]
}
return p;
}

public void union(int p,int q){
int pRoot = find(p);
int qRoot = find(q);
if(pRoot == qRoot) return;
if(sz[pRoot] > sz[qRoot]){ //增加操作数,降低触点深度,提高find效率
ids[qRoot] = pRoot;
sz[pRoot] += sz[qRoot];
}else{
ids[pRoot] = qRoot;
sz[qRoot] += sz[pRoot];
}
count--;
}

1
2
3
4
5
6
publlic static void main(String[] args){
Component c = new ConcreteComponent1();
ConcreteDecorator decorator = new ConcreteDecorator();
decorator.setComponent(c);
decorator.operation();
}

介绍

意图:动态的给实体类添加新功能

常用实现方式:

  • 继承:每添加一个共能,都要添加/修改子类。==导致耦合性强,子类膨胀==。
  • 装饰器:显式调用,==动态==的为实体添加功能。子类与装饰类可以独立拓展。==导致耦合性低,子类独立发展,装饰类可复用==。
  • 代理:隐藏了真实调用对象,使用者无感知。

缺点: 多层装饰比较复杂。即,将传入过实体类的装饰器,再传入装饰器。

多层装饰[^添加多个功能]

多个装饰器,定义不同的功能。

  1. 将实体传入装饰器,获得返回结果
  2. 将返回结果再次传入一个装饰器
  3. 得到一个额外添加了两个功能的实体

静态代理

由程序员或者自动生成工具生成代理类,然后进行代理类的编译和运行。在代理类、委托类运行之前,代理类已经以.class的格式存在。

介绍

意图: 给实体类添加功能

注意事项:

  • 装饰器的阉割版,只有一个代理类实现时可以使用
  • 可以用继承实体类替代

JDK动态代理

在程序运行时,由反射机制动态创建而成。

介绍

意图: 动态为实体类添加功能

优点:

  • 代理工厂类与实际调用类完全解耦

缺点:

  • 返回的代理类需要强制转换为实体类类型

注意事项:

​ 有时为了隐藏实体类转换过程,将proxyFactory继承Subject,重写所有方法的的实现。参考:mybatis中对SqlSessionFactory的处理[^org.apache.ibatis.session.SqlSessionManager]

CGLIB动态代理

基于子类的动态代理类创建,与JDK动态代理区别:无需接口类

此处省略类图,自己脑补。把JDK动态代理类图中,接口类Subject去掉即可。

介绍

详见JDK动态代理-介绍

主要用途

  1. 远程代理(remote proxy),为远程对象提供一个本地的代理对象。例:RMI,EJB,local bean
  2. 虚拟代理(virtual proxy),对象在第一次被使用时才会创建,用代理对象替代真实对象初始化。
  3. 写入是复制代理(copy-on-write proxy),控制对象的复制,在第一次对复制后对象执行写操作时,才会真的去复制。是虚拟代理的一个变体。
  4. 保护代理(protection (access)proxy),为不同客户提供不同级别的目标对象访问权限。
  5. 缓存代理(cache proxy),为开销大的运算结果提供缓存,允许不同客户共享。降低访问延迟
  6. 防火墙代理(firewall proxy),控制网络资源的访问,保护主题免受恶意客户的伤害。
  7. 同步代理(synchronization proxy),在多线程情况下,为主题提供安全的访问。
  8. 智能引用代理(smart reference proxy),当一个对象被引用时,提供一些额外功能。例如:记录调用次数等。
  9. 复杂隐藏代理(complexity hiding proxy),为了隐藏一个类的复杂度,并进行访问控制,有时也称为外观代理(facade proxy)。效果与外观模式类似,只是采用代理控制访问。

[^org.apache.ibatis.session.SqlSessionManager]: https://github.com/mybatis/mybatis-3/blob/master/src/main/java/org/apache/ibatis/session/SqlSessionManager.java 源码地址

一直以来,我们在交易系统中使用BigDecimal类做运算。这成为了一种习惯,导致我忘记了为什么用它。

原因:精度丢失

​ 不管在 java 还是 js ,亦或者 python 中。

​ 0.1 + 0.2 = 0.30000000000000004

​ 所以,为了计算准确,我们使用BigDecimal

js中不存在原生的BigDecimal

替代方案big.jsAPI

Double

img

sign exponent fraction
1位 11位 52位
63 62-52(实际的指数大小-1024 ~ +1023) 51-0

例:3.5

sign: 0

exponent: 10000000000

fraction: 1100000000000000000000000000000000000000000000000000

指数部分10000000000-1023=1

尾数部分11

根据规约形式尾数的整数部分为1

综上,得==1.11B * 10^+1^ = 11.1B = 21 + 20 + 2-1 [^二进制位表示 ] = 2^1^ + 2^0^ + 2^-1^ = 3.5==

3.5刚好可以用二进制表示,但是还有许多小数是无法用二进制表述的

例如:0.1

sign: 0

exponent: 01111111011

fraction: 1001100110011001100110011001100110011001100110011010

无法使用2x + 2y + …这样的形式表示

所以 0.1 + 0.2 == 0.3 false

BigDecimal

解决方案:不适用二进制,而是使用==十进制(BigInteger) + 小数点位置(scale)==来表示。

例如:100.001

unscaledValue:100001

scale:3

即,100.001 = 100001 * 10^-3^

运算操作

加法

x*10^-n^ + y*10^-m^ = x*10^-n^ + (y*10^-m+n^)*10^-n^ = (x + y*10^-m+n^) * 10^-n^ ,其中n > m

乘法

x*10^-n^ * y*10^-m^ = (x*y) * 10^n+m^

BigInteger

可以表示任意精度的整数,当你使用long类型进行运算的时候,可能产生长度溢出,此时就可以考虑使用BigInteger。BigDecimal就是使用它作为backend。

实现方案:==使用数组来存储==

参考资料

[TOC]

分类

定义:已有类别信息,通过对已知分类数据的训练和学习,找到不同类的特征。再对未分类数据进行分类。

特征:

  • 属于监督学习

常见算法:

  • 决策树
  • 朴素贝叶斯
  • 支持向量机(SVM)
  • 神经网络
  • K-最近邻(k-nearestneighbor, KNN)
  • 模糊分类法

聚类

定义:未知分类信息,通过聚类分析将数据或者用户分为几个群体。聚类不需要对数据进行训练和学习。

特征:

  • 属于无监督学习

常见算法:

  • K均值(K-means)
  • K中心点(K-medoids)
  • clarans
  • 基于层次(birch, cure, chameleon)
  • 基于密度(dbscan, optics, denclue)
  • 基于网格(sting, clique, wave-cluster)

以下均摘录自知乎

## 准备工作

注意 本文主要针对Windows平台和Hexo 3.x

### 了解Hexo

>A fast, simple & powerful blog framework

Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。
http://hexo.io**

### 安装GIT
[GitHub Windows](GitHub for Windows**)

简单可依赖,安装完成后依据提示操作即可,So Easy

###安装Node.JS
Node.JS

注意 安装完成后添加Path环境变量,使npm命令生效

``` bash
C:\Program Files\nodejs\node_modules\npm
```

### 安装Hexo

配置好GitHub家目录后,双击桌面上的Git Shell,输入npm命令即可安装

``` bash
npm install -g hexo-cli
npm install hexo –save
```

文档**

-–

## Hexo初始化配置

### 创建Hexo文件夹
安装完成后,根据自己喜好建立目录(如E:\kuaipan\GitHub\hexo),进入Git Shell切换到该路径下E:\kuaipan\GitHub\hexo执行以下指令
``` npm
hexo init
```

### 安装Hexo插件

``` bash
npm install hexo-generator-index –save
npm install hexo-generator-archive –save
npm install hexo-generator-category –save
npm install hexo-generator-tag –save
npm install hexo-server –save
npm install hexo-deployer-git –save
npm install hexo-deployer-heroku –save
npm install hexo-deployer-rsync –save
npm install hexo-deployer-openshift –save
npm install hexo-renderer-marked@0.2 –save
npm install hexo-renderer-stylus@0.2 –save
npm install hexo-generator-feed@1 –save
npm install hexo-generator-sitemap@1 –save
```

### 本地查看效果
继续执行以下命令,成功后可登录localhost:4000查看效果
``` bash
hexo server
```

### Hexo简写命令
``` bash
hexo n #new
hexo g #generate
hexo s #server
```
-–

## 部署静态网页到GitHub

### 注册设置GitHub

  1. 登录[GitHub](GitHub · Build software better, together.**),注册自定义用户名如wsgzao
  2. 在主页右下角创建New repository,name必须和用户名一致如[http://wsgzao.github.io**](https://link.zhihu.com/?target=http%3A//wsgzao.github.io)
  3. 首次创建耐心等待10分钟左右审核,之后即可访问静态主页如HelloDog**

### 同步内容至GitHub

  1. 下载[GitHub Windows](GitHub for Windows**)
  2. 设置Local pathE:\快盘\GitHub\
  3. 运行Git Shell切换到如E:\快盘\GitHub\hexo路径下
  4. 执行hexo g命令生成public文件夹
  5. 把生成的内容全部拷贝到Local path或其子目录
  6. 运行GitHub确认修改信息后执行右上角的Sync同步
  7. 最后访问主页观察效果

[GitHub Pages**](GitHub Pages**)

-–
## 域名和DNS

### 域名推荐

> GoDaddy makes registering Domain Names fast, simple, and affordable.
【推荐理由】两个字“靠谱”,支持支付宝,附优惠码链接

[Domain Names**](Domain Names**)
[Godaddy Coupon Code**](Godaddy Coupon Code**)

### DNS推荐

>致力于为您提供最稳定、最安全的域名解析服务
【推荐理由】依然是两个字“靠谱”,感谢他们一直以来对于公益的坚持

DNSPod-免费智能DNS解析服务商**

### 设置CNAME

  1. 在Github的网站目录下创建CNAME文件
  2. 填写自己的域名如[http://hellodog.com**](https://link.zhihu.com/?target=http%3A//hellodog.com),保存结束
  3. 登录DNSPod,先添加域名,然后添加记录,设置如下

我要开始写笔记了

这里主要记录:

  1. 平时遇到的问题,解决的方法
  2. 学习经历
  3. 碎碎念

嗯,暂时就想到这么多