设计模式剖析

1、设计模式概述

设计模式对于工作一两年的同学来讲并不陌生,甚至觉得设计模式很高深,尤其对于新手来讲,好像有些设计模式知道,一到实际应用中,又使用不上,久而久之,有一种"可远观而不可亵玩焉"的感觉。本文用另一种思路来分析设计模式,探究设计模式的奥秘。

1.1 何为设计模式

设计模式就是"设计的模式",前面是定语,是修饰,重点是模式,模式我们都知道,是一种可复制的经验、经历、榜样,如"广东模式"等。那为什么要用模式呢?其一是前人有走过,后面不用再踩坑;二是具有可操作性,可直接复用。所以到这里得出一个结论:模式是为了解决可复用性!

前面的设计到底是什么意思?软件设计、架构设计 ......,设计模式其实是一个简写,它的全称是这样的:设计模式-可复用面向对象软件的基础,到这里就明白,这里的设计其实是面向对象设计,说白了设计模式就是面向对象设计总结出来的模式集合。

1.2 设计模式到底要解决哪些问题

回答这个问题,至少有一个答案我们是知道,那就是复用性,因为模式是可复用的,除了这一点,其实还有一点,那就是可扩展性。为何这样说,回到上面的分析上去,设计模式其实是面向对象设计总结出来的模式集合,面向对象主要解决什么问题?答:可扩展性(上一篇文章有专门写面向对象)。所以综合一下,设计模式主要解决两个问题:可复用性和可扩展性

1.3 设计模式本质

设计模式的本质就是利用面向对象的技术手段去达到设计的可扩展性和可复用性,所以面向对象是设计模式的内核,脱离了面向对象去谈设计模式那是耍流氓的。大师又用简单、经典的话概括出:找到变化、封装变化!问题来了,那如何找到变化呢?又如何封装变化呢?大师笑而不语。所以设计模式的本质就是:找到变化并封装变化!(本质的东西是简单的、通俗易懂的、美的,从本质入门,反推就可以寻找到答案了)

2、经典设计经验

如何去评价一个设计是好的还是坏的呢?肯定有一个标准,那就是:高内聚、低耦合。它的意思是不同的功能之间耦合低,不要修改一个点就牵一发而动全身,一个功能只完成它负责的职责,改动点也就是这一块,不牵涉到其它的地方。

上面给出了评价的标准,那怎么做具有可操作性呢?还是从这个话来分析:内聚是功能内聚,一个功能只专注它做的事,这个比较好理解,大师给它起了一个好听名字叫单一职责;"独木不成林,单丝不成线",事物之间具有关联性,关联就有产生耦合,完全独立存在是没有耦合的,这在现实中还是比较少,大部分的还是有关联性的,关联避免不了,那只能让关联产生的耦合度变低,从这个意思出发,从面向对象中的剖析可以知道,相关联的东西可能会变化(找到变化),如何去处理变化呢?面向对象给出了技术手段就是多态,所以答案已经呼之欲出了,低耦合的实现技术手段是多态(封装变化)。

还记得上面的设计模式本质么?是找到变化、封装变化,大师在面向对象中已经给出了答案。大师又身体力行,高度凝练出几条设计经验可以使得设计变得低耦合,个人觉得只要满足下面几条,就可以了,不像教科书上陈列出一大堆教条,反而让人迷糊了,其实它们的本质作用是一致的。

  • 单一职责:这个不用讲了,就是专注于一个功能。
  • 开闭原则:对内关闭修改,对外开放修改,这个很重要,不能修改原有的类,要修改说明不灵活,有变化就要修改原有的内容,然而对外开放就不一样,有变化你就新增内容,不用对原有的逻辑有影响。这样是不是耦合度变低了呢?开闭原则是依赖于下面的面向接口编程讲的,开闭是目的,面向接口编程是实现手段。
  • 面向接口编程:或者是面向抽象编码,意思是依赖于抽象,不依赖于具体的实现,如果与具体的实现相关联性大,那么灵活性不大,面向接口编程又与下面的优先使用组合配合使用。
  • 优先使用组合:这里还是比较好理解的,事物之间有关联,一个类中包含另外一个类,又考虑变化,就用一个接口来封装变化,有新变化,按照接口实现一个具体的实现即可。

至此,设计模式中经常使用到的手段就是接口编程和组合,也即设计模式核心问题解决的方案都是在面向对象中。

3、设计模式实战

假如有这样的一个需求:不同部门打印需求不同,宣传部门要求加上页头和页首,业务部门要求加上水印(请勿外传字样)......,请设计一个打印系统。

3.1 渣渣的设计

拿到这个需求,发现不同部门的打印需求是不一样,所以一个简单的设计方案出来了,设计一个打印接口,不同的部门去实现这个接口类,如果有新部门增加,再写一个实现类就可以了。假如一个部门又改了打印需求,怎么办?再需要重新写一个类。

// 打印接口
interface Print{
public void print();
}

// 宣传部门实现
XuChuangDepartment implements Print{
public void print(){
。。。
}
}

// 业务部门实现
YeWuDepartment implements Print{
public void print(){
。。。
}
}

这样的设计问题在于,实现的类过多,可复用性不好,划分的粒度太大了。

3.2 小白的设计

小白拿到这个需求,想到打印分为打印页头、页尾、页内容和其它附属的内容(如水印或者背景图片),想到了模板的方法,写下如下代码:

// 打印模板类
abstract Print(){
abstract void printHeader();
abstract void printFooter();
abstract void printBody();
abstract void printNewRequired();

void print(){
printHeader();
printBody();
printFooter();
printNewRequired();
}
}

// 宣传部门实现
XuChuangDepartment extends Print{
printHeader(){
。。。
}

printFooter(){
。。。
}

printBody(){
。。。
}

printNewRequired(){
。。。
}

}

这里的设计问题与渣渣的设计问题一样,如果自己部门再提打印需求,要么修改现有的代码,要么重新实现一个类,粒度还是过于粗糙。

3.3 老白的设计

老白仿佛看到了问题所在,在前面的基础上进行修改,他是这样设计的,把打印页头、页尾设计成接口,这样的粒度就变小了,伪代码如下:

class Print{
IPrintHeader printHeader;
IPrintFooter printFooter;
IPrintBody printBody;
IPrintOther printOther;

void print(){
if(printHeader != null){
printHeader.print();
}

。。。
}
}

老白设计其实也不是很好,正确的做法是用装修模式来设计,最基本的打印需求就是打印出内容,其它的页头、页尾、水印都是附加功能。

4、总结

设计模式的本质就是找到变化、封装变化,所以在创建型、结构型、行为型设计模式中,它们都是在找到变化并封装变化,封装的手法综合了组合、继承、多态来实现,灵活地运用设计模式可以使得设计变得更灵活性,即可扩展性,重要的话说三遍:可扩展性、可扩展性、可扩展性!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值