CSS 知识

选择器的特殊性

根据选择器的特殊性决定规则的次序。具有更特殊选择器的规则优先于具有一般选择器的规则。如果两个规则的特殊性相同,那么后定义的规则优先。

选择器的特殊性分成4个成分等级:a、b、c 和 d。

  • 如果样式是行内样式,那么 a = 1.
  • b 等于 ID 选择器的总数。
  • c 等于类、伪类和属性选择器的数量。
  • d 等于类型选择器和伪元素选择器的数量。
特殊性示例
-----------------------------------------------------
|  选择器                              |  特殊性      |
|-------------------------------------|-------------|
|  style=""                           |  1,0,0,0    |
|  #wrapper #content {}               |  0,2,0,0    |
|  #content .datePosted {}            |  0,1,1,0    |
|  div#content {}                     |  0,1,0,1    |
|  #content {}                        |  0,1,0,0    |
|  p.comment .datePosted {}           |  0,0,2,1    |
|  p.comment {}                       |  0,0,1,1    |
|  div p {}                           |  0,0,0,2    |
|  p {}                               |  0,0,0,1    |
-----------------------------------------------------

参考文献

Andy Budd, Simon Collison, Cameron Moll, 陈剑瓯(译). 精通 CSS 高级 Web 标准解决方案. 人民邮电出版社.

博客评论系统的更新历程

这个博客站点使用 Github Pages 搭建,能够提供静态页面的展示,但是没有一套现成的评论系统。从前年开始,就一直在尝试各种方法增加评论功能,每次更新都是方案的重大改变。最终的实现还是使用传统方案,自建服务器,使用数据库存储。应该以后就会围绕这个方案完善下去,好在博客一直没啥人气,我可以慢慢折腾 ==。

Read More

设计模式

前言

模型是在某情景(context)下,针对某问题的某种解决方案。

根据模式的目标可以分成三个不同的类目:创建型、行为型和结构型。

面向对象基础:抽象、封装、多态、继承

面向对象设计原则

  • 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

  • 多用组合,少用继承。

  • 针对接口编程,而不是针对实现编程。

  • 为了交互对象之间的松耦合设计而努力。

  • 对扩展开放,对修改关闭。

  • 要依赖抽象,不要依赖具体类。

  • 最少知识原则:只和你的密友谈话。

  • 别找我,我会找你。(由超类主控一切,当它们需要的时候,自然会去调用子类。)

  • 一个类应该只有一个引起变化的原因。

设计模式分类

中英文对照

序号 英文名 中文名
1 Abstract Factory 抽象工厂
2 Builder 生成器
3 Factory Method 工厂方法
4 Prototype 原型
5 Singleton 单件
6 Adapter 适配器
7 Bridge 桥接
8 Composite 组合
9 Decorator 装饰者
10 Facade 外观
11 Flyweight 享元
12 Proxy 代理
13 Chain of Responsibility 职责链
14 Command 命令
15 Interpreter 解释器
16 Iterator 迭代器
17 Mediator 中介者
18 Memento 备忘录
19 Observer 观察者
20 State 状态
21 Strategy 策略
22 Template Method 模板方法
23 Visitor 访问者

组织编目

根据两条准则对模式进行分类。

第一是目的准则,即模式是用来完成什么工作的。模式根据其目的可分为创建型、结构型、或行为三种型

第二是范围准则,指定模式主要是用于类还是用于对象。

目的
创建型 结构型 行为型
范围 Factory Method Adapter(类) Interpreter
Template Method
对象 Abstract Factory Adapter(对象) Chain of Responsibility
Builder Bridge Command
Prototype Composite Iterator
Singleton Decorator Mediator
Facade Memonto
Flyweight Observer
Proxy State
Strategy
Visitor

设计模式支持的可变的方面

软件开发过程中永远不会变化的就是“变化”。我们需要考虑如何应对变化,使得变化发生时不会引起重新设计。最主要的一点是 封装变化 的概念。

下表列出了设计模式允许你独立变化的方面,你可以改变它们而又不会导致重新设计。

目的 设计模式 可变的方面
创建 Abstract Fatory 产品对象家族
Builder 如何创建一个组合对象
Factory Method 被实例化的子类
Prototype 被实例化的类
Singleton 一个类的唯一实例
结构 Adapter 对象的接口
Bridge 对象的实现
Composite 一个对象的结构和组成
Decorator 对象的职责,不生成子类
Facade 一个子系统的接口
Flyweight 对象的存储开销
Proxy 如何访问一个对象;该对象的位置
行为 Chain of Responsibility 满足一个请求的对象
Command 何时、怎样满足一个请求
Interpreter 一个语言的文法及解释
Iterator 如何遍历、访问一个聚合的各元素
Mediator 对象间怎样交互、和谁交互
Memento 一个对象中哪些私有信息存放在该对象之外,以及在什么时候进行存储
Observer 多个对象依赖于另外一个对象,而这些对象又如何保持一致
State 对象的状态
Strategy 算法
Template Method 算法中的某些步骤
Visitor 某些可作用于一个(组)对象上的操作,但不修改这些对象的类

设计模式描述

1. Abstract Factory / 抽象工厂

意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

2. Builder / 生成器

意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

3. Factory Method / 工厂方法

意图:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

简单工厂不是设计模式,而是一种编程习惯。它经常被用于封装创建对象的代码。

4. Prototype / 原型

当创建给定类的实例的过程很昂贵或很复杂时,就使用原型模式。

5. Singleton / 单件

确保一个类只有一个实例,并提供一个全局访问点。

6. Adapter / 适配器

将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

7. Bridge / 桥接

使用桥接模式不只改变你的实现,也改变你的抽象。

8. Composite / 组合

允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

9. Decorator / 装饰者

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

10. Facade / 外观

提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

11. Flyweight / 享元

意图:运用共享技术有效地支持大量细粒度的对象。

如想让某个类的一个实例能用来提供许多“虚拟实例”,就使用享元模式。

12. Proxy / 代理

为另一个对象提供一个替身或占位符以控制对这个对象的访问。

13. Chain of Responsibility / 责任链

当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式。

14. Command / 命令

将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

15. Interpreter / 解释器

使用解释器模式为语言创建解释器。

16. Iterator / 迭代器

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

17. Mediator / 中介者

使用中介者模式来集中相关对象之间复杂的沟通和控制方式。

18. Memento / 备忘录

当你需要让对象返回之前的状态时(例如,你的用户请求“撤销”),就使用备忘录模式。

19. Observer / 观察者

定义对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

20. State / 状态

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

21. Strategy / 策略

定义算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

22. Template Method / 模板方法

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

23. Visitor / 访问者

当你想要为一个对象的组合增加新的能力,且封装并不重要时,就使用访问者模式。

MVC 复合模式

MVC 包含观察者模式、策略模式和组合模式。

模型利用“观察者”让控制器和视图可以随最新的状态改变而更新。
视图和控制器实现了“策略模式”,控制器是视图的行为,如果你希望有不同的行为,可以直接换一个控制器。
视图内部使用组合模式来管理窗口、按钮以及其他显示组件。

反模式

反模式告诉你如何采用一个不好的解决方案解决一个问题。

反模式看起来总像是一个好的解决方案,但是当它真正被采用后,就会带来麻烦。通过将反模式归档,我们能够帮助其他人在实现他们之前,分辨出不好的解决方案。

参考文献

Eric Freemain, Elisabeth Freeman, Kathy Sierra, Bert Bates. Head First 设计模式. 中国电力出版社.

Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. 设计模式-可复用面向对象软件的基础. 机械工业出版社

JavaScript 原型链和继承机制

核心概念

js 中的继承不同于 C++、Java 此类面向对象语言,其继承机制基于原型链。当需要在 js 中使用继承机制时,构造正确的原型链即可实现继承。

js 原型链机制中的各对象之间的关系如上图所示。构造正确的符合继承行为的原型链的关键在于,构造函数的 prototype 属性以及 prototype 的 constructor 属性。

为构造函数构造原型链

1
2
3
4
5
6
function extend(Child, Parent) {
var F = function() {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
}

为构造函数构造原型链处理的是构造函数,用于实例化出任意多的对象实例。

为对象实例构造原型链

1
2
3
4
5
function object(o) {
function F() {}
F.prototype = o;
return new F();
}

为对象实例构造原型链是一次性的行为,所以 F.prototype.constructor 不需要严格设定。

参考文献

http://www.mollypages.org/tutorials/js.mp

Javascript – How Prototypal Inheritance really works

Javascript面向对象编程(二):构造函数的继承

Javascript面向对象编程(三):非构造函数的继承

视图裁剪

前言

HttpServerDebug 实现了类似 Xcode Debug View Hierarchy 功能。客户端提供信息,前端绘制并提供交互能力,实现视图调试功能。

视图调试其中一项功能是 Show Clipped Content,虽然不知道 Xcode 的实现方式,但是通过计算我们也可以拿到同样的信息。本文说明 HttpServerDebug 中的实现方案。

Read More

Objective-C Block

前言

本文内容主要来自 Pro Multithreading and Memory Management for iOS and OS X with ARC, Grand Central Dispatch, and Blocks 这本书,参考这篇文章

Block 是语言级别的语法,是 C 语言的扩展。Block 可以解释为“包含了局部变量的匿名函数(anonymous functions together with automatic (local) variables)”。本文不多说 Block 的使用方法,着重讨论 Block 的实现机制。

Read More

排序算法,伪代码实现

一、插入排序

1. 直接插入排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 使用插入排序算法,将目标数组从小到大排列
* @param array 待排序的目标数组
* @param n 数组长度
*/
void InsertSort(int array[], int n) {
int i, j;
int tmp;
for (i = 1; i < n; i++) {
// 遍历待排序元素
tmp = array[i];
for (j = i - 1; j >= 0 && array[j] > tmp; j--) {
// 遍历已排序元素
array[j + 1] = array[j];
}
array[j + 1] = tmp;
}
}

时间复杂度 O(n^2),空间复杂度 O(1)。直接插入排序是稳定的排序算法。

Read More