可复用技术

自从软件开发成为一项严谨的职业以来,程序员们都在寻找轻松工作编写完美代码的方法。可惜的是,Brooks博士在他的名著《人月神话》中,就论述了软件本身所具有的复杂性,这个世界上没有能够一劳永逸的银弹。

但现实却是,我们的工作和生活需要越来越多的软件来支撑。所以为了减少软件开发的工作量,降低系统隐藏的bug量,有许多理论被提出以解决这一问题。

可复用技术可以说是非常直观的想法,这来源于人们在其他工程领域的经验。例如在制造业、建筑工程中,大量的基础部件都是标准的通用件。

那么软件是不是也可以由一组标准的、可重复使用的子程序构成呢?

在结构化编程语言时代,业界众多公司都做出过努力,但最终仍然没有形成统一的认识。大家都认为自己的函数库是最好用的,以至于给C语言的程序员贴上了喜欢重复发明轮子的标签。

在开发语言进入面向对象的时代之后,可复用技术终于有了大步的发展。这得益于面向对象技术的基本特点,包括类的概念、继承、多态等,以及后来的高级特性,包、异常、垃圾回收等。(详细内容可参见我的历史文章《学好面向对象编程语言的关键,在于掌握它们的共通结构与特性》)

毫无疑问,面向对象开发语言流行之后,类库是可复用技术的第一个成果。为了让代码可重复使用,程序员很自然地就会把类似代码都归总到类中。这些类汇聚在一起,就形成了类库。

接下来为了方便讨论,将会使用C语言和Java语言进行说明。

先提出一个问题,就是要在不同平台上实现IO类的操作,代码差异有多大?例如在linux上和Windows上生成一个网络套接字的方法。

如果用C语言来编写,那么linux上是这样的:

#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
int createSock()
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

在Windows上则看起来是这样:

#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
int createSock()
    //初始化WSA
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0)
		return 0;
	//创建套接字
	SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

我想,如果是初学者,看到这两段内容迥异但功能却一样的代码,估计内心是相当崩溃的吧。起码我当年学习网络编程时就是这样。拿着linux版本的那份代码,放到Windows上去修改编译直至通过,这中间趟了多少坑,都远不止代码上能看到的这些差异。

即使编译通过,同名函数的功能还存在差别呢。细心的同学们应该会注意到,在不同的平台上,socket()函数的返回值类型都不相同。

幸好,在Java语言里,这一切都不是问题了。Java创建套接字:

import java.net.Socket;
public static void main(String args[]) throws Exception {
    String host = "127.0.0.1"; 
    int port = 4321;
    Socket socket = new Socket(host, port);

上面这段代码可以放到任何一个平台上运行,并且预期的行为都是一致的,不存在差异。而面向对象语言都会拥有一个内置的标准类库,调用它们就如同调用C语言的内置库函数一样。

当然,Java的类库实现IO操作要依赖各个平台的系统调用接口。但这些差异处完全可以封装到类库中去,对于Java程序员来说,他们根本不必关心这些差异,只要掌握了Java类库的方法就可以。

这是类库对软件开发带来的可复用之处:更容易形成标准化的操作,避免重复发明轮子,屏蔽系统底层的差异。程序员可以摆脱技术细节的纠缠,专注于业务实现。

随着互联网业务的快速发展,在构建业务应用层面,人们又有了新的需求。最典型的情况就是web快速增长的情况下,基于http技术的服务成了最普遍的要求。

当然,Java类库中也包含了http的操作方法。这只是解决了http协议相关的操作,但web还包含了一系列对请求进行响应的过程。而这些业务过程,大多数时候在技术上并无太大差异。于是,在更高层面上可复用的框架技术就出现了。

从使用目标与规模上来说,框架可以分为两大类。一是囊括了开发工具、运行时环境等,例如微软的.net framework。在某种程度上,这甚至已经成为了一个商业概念。

另一类则是单一语言开发,有特定用途的功能集合。我们接下来要讨论的,则是这种功能性框架。

例如Structs框架就实现了MVC模式的整套流程,程序员使用这个框架,就不必再关心如何去构建MVC的功能逻辑了。还有Hibernate框架,就帮助程序员可以轻松构建对象与关系数据的映射,程序员同样不必去实现ORM的功能逻辑了。

从框架的技术特点可以看出来,它包含了一套实现业务逻辑的流程。程序员要做的,就是在这套已有的流程之中添加自己的业务处理。

这个技术特点在业界有个特定的称谓:好莱坞原则。这条原则的本意是说在好莱坞,电影制作人在挑选演员时会傲慢地说“Don’t call us, we will call you.” 在框架设计中,则被引申为应该由框架来调用业务处理,而不是业务代码去调用框架。

对于初学者来说,了解这一点非常重要。因为框架的单方面调用特性,许多细节都不会暴露在外。程序员在学习框架时,往往会感觉无从入手。因为它没有明确的从哪里开始到哪里结束的过程,就是继承一个类,然后重写调用方法,编译运行就可以了。

至于这个方法什么时候会被调用,什么条件下会被触发,基本上要靠猜。所以,了解了好莱坞原则以后,程序员在初学框架时,起码可以做到心中有数,能够从框架的整体逻辑上去分析,被重写的方法调用时机是什么。

设计模式自从被提出以来,一直是业界的热门话题,今天我想从软件开发可复用的角度谈一谈它。

无论是类库还是框架,它们都是实在可用的代码,而设计模式则不一样,它是写代码的一种参考规范。打个比方的话,类和框架就是锤子和模具,而设计模式则是使用说明书。

从时间线来说,设计模式是后来出现的,因为它并不是凭空创造出来的,而就是来自于对代码本身的提炼与总结。

1995年,包括Erich Gamma等四人合著出版的《设计模式:可复用面向对象软件的基础》一书,可以说是这一领域的开山之作。这四人之后也被江湖尊称为GoF,意即Gang of Four。

在这本书中,对一些典型的代码组织和结构的问题,提出了相应的解决办法。由此而汇集成了23种设计模式。你可以说它们是一些技巧,或者是一些习惯用法。有了设计模式作为思想武器,可以将复杂的业务逻辑分解并实现。

前人智慧总结的好处,就在于它是历经实践所检验的,对于程序员来说,可以放心大胆地去使用。不过有一点还是需要程序员所警醒的,就是不要为了模式而模式,好像哪段代码套不进一个模式里都睡不着觉了。

GoF所提出的设计模式,它们都是基于面向对象技术的,因此熟悉面向对象的基本概念是十分重要的。包括前文提及的类、封装、继承、多态等。

从用途上说,设计模式被分为三个方面。创建型模式,用来指导如何为业务场景以适合的方式生成对象;结构型模式,用来拆解对象间复杂的关系,简化调用结构;行为模式,对于包含了一系列复杂操作的流程,提出了简洁可用的办法。

23种设计模式分类:

  • 创建型模式:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式;
  • 结构型模式:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式;
  • 行为模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

当然,随着软件工程的不断发展,也有越来越多的设计模式被提出,并在业界得到应用。可以说,只要程序员需要编写代码完成工作,设计模式就一直会是热门话题。

程序员要掌握好软件开发的可复用技术,前提还是要熟悉面向对象的基本概念,熟练使用一门面向对象编程语言。

有了这些基础,在学习类库和框架时,就可以做到提纲挈领,不会迷失于大量的细节之中。当工作需要用到一项功能时,不必急于自己发明轮子,可以搜索开源项目,快速了解其原理并应用到自己的工作中。

而学习设计模式,还真的不是一件可以速成的事情。这需要程序员在不断编写代码的过程中去领会。因为在代码量还没有足够积累的情况下,很容易就陷入到唯设计模式的教条主义中去。

实际情况往往是千差万别的,应用设计模式也不是一成不变的。这需要程序员从实际出发,采用最适合的方法去解决问题。程序员应该记住的是,设计模式是一组原则,而不是配方。

关于可复用技术,也希望看到更多高手们留下自己的看法。

可复用技术自从软件开发成为一项严谨的职业以来,程序员们都在寻找轻松工作编写完美代码的方法。可惜的是,Brooks博士在他的名著《人月神话》中,就论述了软件本身所具有的复杂性,这个世界上没有能够一劳永逸的银弹。但现实却是,我们的工作和生活需要越来越多的软件来支撑。所以为了减少软件开发的工作量,降低系统隐藏的bug量,有许多理论被提出以解决这一问题。可复用技术可以说是非常直观的想法,这来源于人们在其他工程领域的经验。例如在制造业、建筑工程中,大量的基础部件都是标准的通用件。那么软件是不是也可以由一组标准
24种设计模式 文章目录设计原则单例模式工厂模式策略模式门面模式调停者模式责任链模式装饰者模式观察者模式组合模式享元模式静态代理动态代理迭代器模式访问者模式构建者模式适配器模式桥接模式命令模式原型模式模板方法状态模式谈到的一些问题 单一职责原则 一个类别太大,负责单一的职责 高内聚,低耦合 里氏替换原则 所有使用父类的地方,必须能够透明的使用子类。比如子类重写父类的A()方法之后,又重载了很多的A()方法,那么这样子会照成对父类接口方法的歧义 例:List list = n.
第一章 引言一、什么是设计模式二、SmalltalkMVCSmalltalk MVCSmalltalkMVC中的设计模式三、描述设计模式四、设计模式的编目五、组织编目六、设计模式怎样解决设计问题七、怎样选择设计模式八、怎样使用设计模式 一、什么是设计模式 一般而言,一个模式有四个基本要素: 1、模式名 一个助记名,它用一两个词来描述模式的问题、解决方案和效果; 2、问题 描述了应该在何时使用模式,它解释了设计问题和问题存在的前因后果; 3、解决方案 描述了设计的组成成分、它们之间的相互关系及各自的职责和协作
mina4-android description Android TCP框架(基于MINA 2.0.0-M3)、增加Bytes工厂、无需依赖slf4j(新增Mina4Log打印输出日志), 处理Bytes粘包、半包、断包(ByteArrayDecoder),需配置自己的首尾标识符, 如果与首尾标识符相同的数据出现在首尾标识符以内的范围,建议将该数据进行转义, 如这样配置转义规则(假设首尾标识符是0x7e): 0x7e = 0x7d,0x02 如果首尾以内出现标识符,将其转换为0x7d后面紧跟一个0x02 0x7d = 0x7d,0x01 如果首尾以内出现标识符转义字符,不进行转换,在其后面紧跟一个0x01 mina4-android use private void initMain4Android() { final ConnectionConfiguration config =
模式名称 — 一个助记名,它用一两次来描述模式的问题、解决方案和效果。 问题 — 描述了应该在何时使用模式。解释了设计问题和问题存在的前因后果。 解决方案 — 描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。 效果...