设计模式剖析-面向模式编程

这是一篇不成形的论文,新项目开始了,先放水了。以前看设计模式相关的书籍,总是感觉记起来很吃力,当时理解了过后仍是忘记。康德在理性批评前言中有过大致如下的描述:如果我们做一件事情,一旦要达成目的,或是已经达成目的,却发现我们得推翻以前所有的建设而重新开始,对于这门学科,我们还远远没有找到一条可靠的道路。本文给出了设计模式的一个全新的分类视角,使记忆、理解都变得十分容易。我相信这是一条正确的道路。并提出了面向模式的程序设计概念。它融合了面向对象编程、泛型、面向方面编程。并为新模式的产生指明了道路。

设计模式剖析-面向模式编程

摘要

面向对象是设计模式产生的基础。[Gamm94]根据设计模式的特性和适用范围,对设计模式进行了二维的分类。[Zim94b]通过对设计模式间的关系(使用关系、组合关系和相似关系)进行考察,把26中设计模式修正为23种,并对23种设计模式进行了分层划分。[Gamm94]和[Zim94b]对设计模式的分类及关系的考察都脱离了设计模式的基本前提—对象,这直接导致了对设计模式理解上的混乱和使用上的错误。

在[Gamm94]和[Zim94b]的基础上,本文从对象的获取、消息的传递、外观改造、内部元素的探查、行为的泛化等五个基本角度,分析并归类23种设计模式,为设计模式的使用和新模式的产生指明了方向。在编程范式演化分析的基础上,把设计模式提高到编程范式的高度,并提出了面向模式的程序设计。

1 概要

通过识别、命名与抽象面向对象设计中通用的主题[Gamm94],设计模式已成为交流面向对象设计经验的通用机制。通过识别对象、对象间的协作和责任在对象间的分布来捕获设计背后的意图,并从设计模式的特性和适用范围对模式空间给出了二维的分类[Gamm94],设计模式可以更易于应用于实际的软件开发过程中。[Gamm94]忽略了对设计模式间的关系的考察。

[Zim94b]从设计模式间三种关系(即使用关系、组合关系和相似关系)出发,深刻考察了设计模式对(X,Y)之间关系,修正[Gamm94]中26种设计模式为23种,并根据三种关系对模式进行了分层。[Zim94b]的考察也脱离了对象。

面向对象程序设计的基本出发点是对象。本文从对象的从无到有、主动与被动、由外到内、数据与行为等方面,探讨面向对象设计的复杂性;从获取对象、对象通信、外观对象、内观对象、行为范化等5个基本方面分类23种设计模式,并分析类别内与类别间模式的关系与协作;阐明了何处、如何使用设计模式,并为新模式的产生指明了方向。

软件复杂性是软件的固有属性[10]。编程范式通过各种方式来控制系统的复杂性,但并不能消除或是降低系统的复杂性。在结构化程序设计的基础上,面向过程程序设计使用信息流和数据绑定来控制的复杂性。基于信息流和数据绑定,面向对象程序设计通过封装、继承和多态来控制软件系统的复杂性。但封装、继承和多态只控制了某类对象的复杂性,没有考虑获取对象的复杂性、通信的复杂性及其方式的变化、外观变化、内观变化和行为变化等系统运行特性与维护中的易变因素。


设计模式


面向模式程序设计


封装、继承和多态


面向对象程序设计


信息流和数据绑定


面向过程程序设计


结构化程序设计

图 1 编程范式演化

设计模式产生的基础是封装、继承和多态三个面向对象程序设计特性。它封装了系统运行特性与维护中的易变因素,是封装、继承和多态对复杂性控制的完整的补充。任何设计模式一但形成,便可独立于封装、继承和多态等面向对象设计特性而独立存在。如可以使用结构化语言C语言来实现设计模式。在面向对象程序设计中,如获取对象、对象通信、外观对象、内观对象、行为范化等5个基本方面均良好地使用了设计模式,称这样的编程范式为面向模式程序设计。设计模式封装了系统运行时特性和维护中的易变因素,面向模式程序设计为系统复杂性分析提供良好的方法。

下面  那部分 都干了什么????

1           获取对象 6

在特定系统中,对象O的单个实例所占用的直接存储空间,即值类型变量所占用的存储空间和引用类型变量所占用的存储空间,是一定的。如不考虑虚拟内存机制,过多的实例对象将会耗尽内存储空间,导致程序崩溃。在面向对象程序设计中,严格控制O的实例个数并建立实例间内存共享机制是高效软件设计的必经之路。从无到有的分析表明,获取对象O实例的复杂性主要表现在四方面:

1)对象选择的复杂性

2)子类型选择的复杂性;

3)构造过程的复杂性;

4)缓存的复杂性。

在GoF设计模式中,可以通过工厂模式、抽象工厂模式、建造者模式、原型模式、单例模式和享元模式等6种设计模式获取一个实例。其中工厂模式和抽象工程模式解决子类型选择的复杂性,建造者模式、单例模式、享元模式和原型模式解决构造过程的复杂性,单例模式和享元模式解决缓存的复杂性。

对象选择复杂性

对象类型选择的复杂性主要表现在依据业务逻辑选择对象类型。使用某个对象与否总是依据当前上下文决定。在传统的面向对象编程中,对象类型是硬编码在特定上下文中的。AOP编程很好的解决了当前上下文与对象类型的选择的解耦问题,我们称其为关注点模式。如选定对象不在本地,可通过两种方式即远程类型加载和动态类型的生成,来获取具体的对象表示。

子类型选择的复杂性

在面向对象编程中,对象可能有多个子类型,需要根据上下文动态决定创建哪个子类型,具有一个维度的变化因素;多个对象的子类型可能相关或是相互依赖,需要根据上下文动态的决定创建每一子类型系列中的哪个对象,具有多个维度的变化因素。工厂模式定义一个用于创建对象的接口,让子对象决定实例化哪一个子对象,封装了具有一个维度的变化因素;抽象工程模式可封装多个维度的变化因素。

构造过程的复杂性

构造过程的复杂性主要表现在复杂对象的构造过程中。建造者模式抓住复杂对象部件组合过程的稳定性和具体部件构造的易变形,将构造过程与表现分离,复用构造过程,实现了各个构造部件子类型的自由选择。原型模式、享元模式和单例模式把构造的复杂性最大的保留在已有的实例中。原型模式和享元模式参数化变易的部分,原型模式通过拷贝原型实例来创建新的对象,享元模式复用已创建的缓存对象。

缓存的复杂性

在程序的某个运行实例中,对象O存在的个数可分为三种情况:存在且仅存在一个实例、存在多个可复用的实例、其它情况。单例模式解决了对象实例存在且仅存在一个的问题;享元模式通过缓存和参数化,实现了实例的复用,有效降低了创建对象的时间开销和大量对象存在所需要的空间开销。在单线程运行环境中,单例模式和享元模式的实现比较简单。但在多线程环境下,需要确保单例模式和享元模式是线程安全的。

3
对象通信 3

按照参与通信的实例个数和方式,实例间的通信可分为:一对一的通信、一对多的通信和链式通信。可以通过函数传参的方式进行对象间的通信,但这种方式在调用对象和被调用对象之间形成硬编码。如函数调用是在同一关注点中,硬编码是可以接受的;如函数调用是在进行关注点的转换,则应禁止硬编码的存在。命令模式和责任链模式都实现了调用者与被调用者之间的解耦。观察者模式通过被调用对象主动注册监听调用对象的某个属性的改变,使调用者可以在不知道被调用对象的情况下独立存在,实现了单方向解耦,被调用对象依然依赖调用对象。

命令模式是一对一的通信模式。封装响应者、命令、参数等信息为一个请求对象,把请求对象参数化以分离请求的调用者和响应者,实现调用者与相应者和具体命名的分离。

责任链模式是链式通信模式。把多个可能处理请求的响应者连成一条链,使请求对象沿着响应者链传递,直到有响应对象处理了该请求。在请求传入责任链后,该模式避免了请求的触发对象和响应对象之间的耦合关系,但第一个响应对象和触发对象之间的调用仍然是硬编码的。

观察者模式是一对多的通信模式。观察者模式实现了单方向解耦,被调用对象依然依赖调用对象。其变种通知模式,通过通知中心的加入实现了调用对象和被调用对象的完全解耦。

2           外观对象 5

组合继承组合模式

称面向对象编程语言提供的根对象类型为Generic;把语言提供的基本数据类型的包装类、字符串和数组称为NGeneric;去除现实世界中的事物的联系,称对其进行孤立抽象所得到的对象为OGeneric,由多个NGeneric对象组合而成;称因多个OGeneric对象相互关联而产生的对象为ORGeneric或RGeneric;称因控制多个对象的关联而产生的控制对象为OCGeneric或BGeneric。

NGeneric集合有自身的复杂性,即集合内部就分为多个等级,如整数是布尔数的超集,逻辑浮点数是整数的超集。我们称在数学上有超集关系的NGeneric类型为不可向上表示的,即不能用有限个布尔数表示任意一个整数,简称为不可表示;如果两个NGeneric类型之间没有超集关系,称这两个类型之间是可表示的。

泛型编程是根据上限制和下限制确定功能代码适用于哪些类型。因此,在面向对象编程中使用泛型技术,任何Generic都可以表现出多态的特性。NGeneric是语言级提供的特性,意义不大;由于业务的复杂性,BGeneric对象系列和OGeneric对象系列及其关系RGeneric对象系列会表现出丰富的多态特性,而这种复杂性将会集中体现于RGeneric对象系列和BGeneric对象系列的复杂性。具体体现于BGeneric对OGeneric接口和RGeneric接口编程,表现出的复杂性与多态性。

GoF23种设计模式中,可通过6种模式来改变一个类型的外观:代理模式、中介模式、适配器模式和门面模式、装饰模式。按照排列的先后顺序,原类型的主体性逐渐丢失,封装类逐渐获得更多的独立性,直到成为其一部分,获取完全的独立性。中介模式不做任何改变,只是协调;适配器模式为单个对象提供一个新的接口;门面模式为多个对象提供一个新的接口;装饰模式添加新的特性,获得了独立性。

代理模式为复杂对象提供一个占位符或是控制访问原始对象的代理。中介模式封装多个对象交互的复杂性,使交互的对象之间不必直接持有其它对象的引用,客户直接使用中介者就可以完成所有的交互需求。中介者只是协调多个对象的通信,降低使用的复杂度,不做任何名称、参数格式、调用结构等方面的改变,不添加任何新的功能;适配器模式修改一个接口的名称或是参数格式或是调用结构等信息,使旧接口满足当前的需求;门面模式定义了一个高层接口,为子系统中的一组接口提供一个一致的界面,使得这一子系统更加容易使用,忽略不用的功能,简化子系统使用的复杂性;装饰模式动态地给一个对象添加一些额外的职责,比子类化更加灵活。

4 内观对象 4

对象作为一个有机的整体,需要探查、了解其内部结构,使其从混沌的非结构状态转换为结构清晰的状态,主要表现在分析与设计阶段中对象结构与行为的分析与设计中。Gof对解释器模式是这样定义的:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。该模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子,有点专家系统的味道;

需要使用不同的对象聚合成新的对象,或是使用同一类对象组合成具有复杂组织结构和交互规则的对象。组合模式用树形结构来表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性;

需要在不暴露内部表示的情况下,遍历聚合的内部元素。迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。

需要在不改变对象内部结构的情况下,动态的改变访问其元素的算法。访问者模式表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

行为异化 5

行为封装对象的能动机制。备忘录模式、策略模式、状态模式和桥接模式是重要的行为异化模式,它们将某些行为异化为单独的类或是多个类。模板模式是面向对象编程的基本特性,并不能算做一个独立设计模式,只是面向对象的一个多态特性。

备忘录模式的目的在于:在不破坏封装性的前提下捕获一个对象的内部状态、在该对象外部保存这个状态、在需要时能够恢复被保存的状态。其本质是将对象状态的捕获、保存和恢复异化为单独的对象,保证面向对象的封装性不被破坏。

策略模式定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

桥接模式将抽象部分与它的实现部分分离,实现部分具有点到线的变化复杂度。

引文

[Gamm93]E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design patterns: Abstractionand reuse in object-oriented de- signs. In O. Nierstrasz, editor, Proceedingsof ECOOP’93, pa- ges 406–431, Berlin, 1993. Springer-Verlag.

[Gamm94]E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Pattern.Addison-Wesley, To Appear, 1994.

[Zim94b]W.Zimmer, Relationships between Design Patterns, Proceedings of the FirstConference on Pattern Languages and Programming, Addison-Wesley, 1994

[10] F.P. Brooks, No Silver Bullets: Essence and Accidents of SoftwareEngineering, Computer, Vol. 20, No. 4 (Apr 1987) 10-19. ?

[7] G. Booch, Object-Oriented Design with Applications (The Benjamin/CummingsPublishing Company,Redwood City, CA , 1991; ISBN: 0-8053-0091-0). ?

时间: 2024-08-07 21:20:30

设计模式剖析-面向模式编程的相关文章

设计模式之代理模式——编程好帮手

代理模式也称为委托模式,是一种结构型设计模式,所谓代理,就是一个人或者机构代表另一个人或者机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.为其他对象提供一种代理以控制对这个对象的访问. 当无法或者不想直接访问某个对象或者访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口. 代理有两种 1)静态代理 2)动态代理 先看看静态代理 静态代理代理模式的UML类图:

从头认识设计模式-策略模式-05-引入设计原则:面向接口编程

这一章节我们来讨论一下怎么解决上一章节扩展性差的问题. 1.解决方案 面向接口编程 2.思路 使用java的多态性,动态的设置导入导出的行为 3.代码清单 在Base里面使用导入导出的接口,然后增加一个通用的导出导入方法,下面的实现中,我们只需要设置不同的导入导出行为,即可通过导入导出方法来实现不同的导入导出结果. package com.raylee.designpattern.strategy.ch05; /** * 1.0 这个类是我们需要使用设计模式改进的原始类,也就是策略模式应用的初始

游戏设计模式——面向数据编程(新)

目录 面向数据编程是什么? 单指令流多数据流(SIMD) 什么是SIMD 为什么需要SIMD 支持SIMD技术的指令集 使用SIMD编程 使用汇编内联 使用指令集库 使用ISPC语言 并行循环 避免Gather行为 CPU缓存(CPU cache) 什么是CPU缓存 为什么需要CPU缓存 CPU缓存预先存的是什么 CPU缓存命中/未命中 提高CPU缓存命中率 使用连续数组存储要批处理的对象 避免无效数据夹杂在连续内存区域 冷数据/热数据分割 频繁调用的函数尽可能不要做成虚函数 重新认识C++ S

说说Python的装饰器模式与面向切面编程

说说Python的装饰器模式与面向切面编程 今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用.概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能. 1. 装饰器入门 1.1. 需求是怎么来的? 装饰器的定义很是抽象,我们来看一个小例子. //edit http://www.lai18.com //date 2

java8 mixins “虚拟字段模式”实现“面向组合编程”

DCI(Data Context Interaction) 面向组合编程,一直是个比较高冷的概念.最近想实践下,发现了一篇不错的文章,翻译一下. 先介绍下背景: JAVA语言是单继承的,所以实现"组合"总是比较绕的.总结下几种实现方式: 实现多接口,具体的行为和状态通过代理实现. AOP/动态代理/其他字节码织入 JVM平台下的其他语言特性,例如scala的Trait,Ruby的mixin 特定框架Apache Zest java8 对接口做了语法上的增强来模拟mixin. 但是不能很

跟王老师学接口(四):面向接口编程:命令模式

面向接口编程:命令模式 主讲教师:王少华   QQ群号:483773664 学习目标 理解面向接口编程的优势 掌握命令模式 一.命令模式 (一)场景 假设你的Boss给你这样一个任务要你处理一个数组.但是没有告诉你,如何处理这个数组,是对其进行输出,还是对其排序.遇到这样的Boss很烦!!! (二) 分析 对于这样的需求,我们第一个想到的就是把数组作为方法的形参,但是我们是否可以把"对数组的处理行为"也作为一个方法的形参传入呢? 因为Java不允许代码块的单独存在,所以我们不可能将&q

游戏设计模式——面向数据编程思想

前言:随着软件需求的日益复杂发展,远古时期面的向过程编程思想才渐渐萌生了面向对象编程思想. 当人们发现面向对象在应对高层软件的种种好处时,越来越沉醉于面向对象,热衷于研究如何更加优雅地抽象出对象. 然而现代开发中渐渐发现面向对象编程层层抽象造成臃肿,导致运行效率降低,而这是性能要求高的游戏编程领域不想看到的. 于是现代游戏编程中,面向数据编程的思想越来越被接受(例如Unity2018更新的ECS框架就是一种面向数据思想的框架). 面向数据编程是什么? 先来一个简单的比较: 面向过程思想:考虑解决

(一)Python入门-6面向对象编程:12设计模式之工厂模式-单例模式

一:工厂模式实现 设计模式是面向对象语言特有的内容,是我们在面临某一类问题时候固定的做法,设计 模式有很多种,比较流行的是:GOF(Goup Of Four)23 种设计模式. 工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类.创建对象进 行统一的管理和控制. [操作] #工厂模式实现 class CarFactory: def creatCar(self,brand): if brand == '奔驰': return Benz() elif brand == '宝马': re

设计模式---创建型模式

一.概况 总体来说设计模式分为三大类: (1)创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. (2)结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. (3)行为型模式,共十一种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 二.设计模式的六大原则 1.开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修