前言
笔者最近在看一本设计模式方面比较好的书,《设计模式之禅》,一大牛同事觉得《重构:改善既有代码的设计》写的更好,结合之前的一些学习体验,笔者有以下感觉:
- 代码完成前设计的艺术,设计模式是代码从无到有的过程中提出的一些设计理念
- 代码完成后优化的艺术,如果我们提出一个原点:“所有的代码写在一个函数”,那么必然涉及到一种拆分代码的艺术。
如果我们以第二个角度看待设计模式,就会有很多有意思的体会。
补充,《Pattern Oriented Software Architecture》中提到,将模式分为三种类型:
- 体系结构模式,比如mvc
- 设计模式
- 惯用法,比如引用计数法
本来主要描述java编程方面
抽取一个类
简单抽取
假设原来有一个比较复杂的类
class A{
void func(){
1.xx
2.xx
3.xx
4.xx
5.xx
}
}
现在我们代码重构,要将步骤234抽出一个类B来,类B需要A的数据初始化,类A需要类B的计算结果。一般有两种方案
-
方案1
class A{ void func(){ 1.xx 2.B b = new B(xx); // b作为A的类成员跟这个差不多 3.xx = b.func(); 4.xx } }
-
方案2
class A{ void func(){ 1. xx 2. xx } } class B{ void func(A a){ 1. xx = a.getxx(); 2. xx 3. a.setxx(); } } class Main{ main{ A a = new A(); B b = new B(); b.func(a); } }
比如spring ioc初始化的一段代码便是如此
// 定义配置文件
ClassPathResource res = new ClassPathResource(“beans.xml”);
// 创建bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 定义读取配置文件的类
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// 加载文件中的信息到bean工厂中
reader.loadBeanDefinitions(res);
两种方式的不同在于:
- 前者只是将相关代码抽取为一个函数,然后到了另一个类里。(本质上只算是抽取了一个函数)
- 后者将相关代码完全抽出来,A类中不用保有任何痕迹,可以算是抽取出了一个类
回调在拆分中的作用
假设我们要抽出的步骤是不连续的,比如将235抽取成一个函数(或B类),那么就要用到回调。(在实际的应用中,会出现“14使用了同样的数据,并且从语义上它们更适合在一起(或在A类)”的情况)
class A{
void func(){
1.xx
2.xx
3.xx
4.xx
5.xx
}
}
class A{
void func(){
1.xx
func2(arg,new Callback(){
void callback(){
4. xx
}
})
}
void func2(arg,callback){
2. xx
3. xx
4. callback()
5. xx
}
}
当然,回调主要用在两个线程交互中。
从拆分的角度看
如果所有功能写在了一个函数里,我们如何拆分它
- 能并行的并行。(设计模式已经不再局限于三大类型,还扩展到多线程模型,io通信模型)
- 无关的代码拆成独立的类
- 可能会变的代码拆成独立的类
拆分的方向有两种
- 将不同的代码拆分成父类和子类,代理类和被代理类,装饰类和被装饰类等,有种类似垂直关系的感觉
- 将不同的代码拆分成类似水平关系的类
避免直接使用直接干活的类
操作系统是为了避免我们直接使用硬件,编程语言是为了避免我们直接使用系统调用,笔者一个很强烈的感觉就是,设计模式(创建型,行为型,结构型)为了避免我们直接使用一个类。
明明可以new一个,偏偏要用工厂。平明可以obj.func
,偏偏要proxyObj.func
这一切都应了《设计模式之禅》中的思想,所有思想的基本原则就是:对扩展开放,对修改关闭。
一切可能变化的部分都不应该让程序猿直接调用(或者抽象成参数),为了应对变化,把一个类拆成多个类(按照变化的可能性拆分,按照上层接口聚合在一起),甚至不惜把变化本身单独拆成一个类。
三个大的分类
这段基本来自摘抄http://design-patterns.readthedocs.io/zh_CN/latest/
,因为编不出比作者写的更好的了。
- 创建型模式,创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离单一职责原则,仅一个对象的创建独立出来,催生了spring的ioc,减少了代码中的创建类代码)。在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。
-
结构型模式(Structural Pattern)描述如何将类或者对 象结合在一起形成更大的结构.结构型模式可以分为类结构型模式和对象结构型模式
- 类结构型模式关心类的组合,一般只存在继承关系和实现关系.
- 对象结构型模式关心类与对象的组合,通过关联关系使得在一 个类中定义另一个类的实例对象(也就是成员变量),然后通过该对象调用其方法。
-
行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化(所以一般先定义好高层接口,定义好交互关系)。行为型模式不仅仅关注类和对象的结构(涉及到结构设计,但不是重点),而且重点关注它们之间的相互作用。
行为型模式分为类行为型模式和对象行为型模式两种:
- 类行为型模式:类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
- 对象行为型模式:对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。
根据“合成复用原则”,系统中要尽量使用关联关系来取代继承关系,因此大部分结构/行为型设计模式都属于对象结构/行为型设计模式。