微信号:imooc-com

介绍:慕课网是一个超酷的互联网、IT技术免费学习平台,创新的网络一站式学习、实践体验;服务及时贴心,内容专业、有趣易学。专注服务互联网工程师快速成为技术高手!

如影随形的设计模式与现实世界

2018-08-16 08:35 Geely


影随形


如影随形指的是好像影子老是跟着身体。比喻两个事物关系密切或两个人关系密切不能分离。出自先秦·管仲《管子·任法》。


设计模式与我们生活的现实世界就是这种如影随形的关系



件危机


那在说这个关系之前呢,我们先从软件设计及开发方面开始说起,20世纪50年代爆发了“软件危机”,面向对象方法也正是在这种情况下诞生的,后来经过大神们的抽象总结,面向对象方法对解决问题的整体思维进行了人性化的革新。



计模式


那设计模式正是建立在面向对象强大思维的基础上被“发现”的,为什么强调是被发现的呢,因为设计模式并不是被发明的。



设计模式的由来


  • 1970年,Christopher Alexander建筑师提出设计模式概念。

  • 1987年,一些设计模式的论文和文章出现了 。

  • 1995年,GOF [四人帮]发表了书:《设计模式-可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software )




实世界的设计原则以及设计模式


上面简单的介绍了一下设计模式的由来,接下来就回归我们现实世界。先从设计原则、内聚及耦合说起。



设计原则


首先在软件设计领域,还有很多软件设计原则,例如开闭原则,对扩展开放,对修改关闭,原则描述言简意赅,如果映射到现实世界,我们如何连接呢?打个简单的比方,现在很多互联网公司上班不需要打卡,有需要打卡的也是弹性的,如弹性上班的考勤而言,弹性上班虽然规定了每天工作要满8小时,但是没规定几点来几点走,那可以简单理解成,对于上班考勤这个事,对每天工作满8小时的修改是关闭的,当然,有胆量的话,你也可以直接和老板说:“老板,我想每天工作满6个小时就想下班”。如果我们是继承的话,对于工作满8小时这个方法,它是final修饰的,开放给子类,能看到,但是并不能重写。对于几点上班,几点下班,这个是一个接口,是开放的,自己来实现(但是记得要满8小时哟,因为会有校验 )。那这个就可以理解成一个现实生活对开闭原则的一个映射。这样的例子还有很多^_^




而符合开闭原则有很多实现方案,包括遵循依赖倒置、合成复用原则等。当然对于继承来说,也是一个提高扩展性的方案,只不过还要看具体的业务场景,而里氏替换原则又对继承等(如方法重载)形成约束。它们的关系很有趣。



内聚及耦合


在内聚及耦合的判断标准上,也是分很多级别的,所以一直存在高低之分,如高内聚、低耦合。这里面就不展开详细阐述了。有兴趣的小伙伴们可以查一下内聚、耦合的分类。



内聚


内聚这个词语是从化学中分子间的作用力引申而来,分子间作用力强则表现为内聚程度高,那在软件设计中,内聚程度的高低,就做为了评比软件设计好不好的标准,就内聚而言打个比方,例如一个非常小型的创业公司初期,就3个人。人少事多还非常杂,那么他们的职责肯定不能是专一的。随着公司发展拿钱融资,规模和员工数量开始增加,事情也多了,这个时候就需要专一职能的员工了,更需要专业化的分工来提高效率,岗位职责清晰。于是,内聚性提高了很多,所以单一职责原则是提高内聚的有效手段。



耦合


一句话理解,活字印刷其实就是一个很好的降低耦合的例子。还有楼宇设计的空调开关,一栋写字楼,如果空调开关设计成要么整栋楼都开,要么整栋楼都关的话。如果单位只在某一层,周六日加班的话,那就幸福了,可能空调费都贵到老板不想让你来加班,这正是一个高耦合的例子,继续思考,那这个开关做到什么粒度合适呢?那依赖倒置原则、合成复用原则、迪米特法则正式为了解耦而来,耦合度越低,就越有利于复用。




权衡有度


但是凡事都有个度,设计原则及设计模式也是要根据实际的业务场景、业务及项目的要求,包括项目的时间、成本、范围、质量、资源、风险等因素反复权衡。如图:




正如三国杀里面的英雄一样,人无完人。




一个软件系统也不可能全部遵守所有的设计原则到100%这个程度。


所以说,学习设计原则、设计模式之后,对业务模型的抽象能力尤为重要,并且要根据实际的业务场景、当时面临的各种困难,来决定如何设计及使用。那这个过程需要我们不断积累、不断思考、总结经验教训,适当做项目复盘,循序渐进,在一些知识点位,温故而知新,螺旋式上升提高自己的这部分能力。当然这里面还要有对业务的前瞻性和预期发展方向评估的能力(主要考虑软件系统的扩展性),但是也不能评估时间太远,评估10年之后的业务发展可能的模型是没有必要的。


通过不断的积累总结,慢慢地自然能练就如何把业务场景及业务模型应用到我们的代码层面了。在设计模式和现实世界中可以游刃有余)。



生活
中关于设计模式的例子


玩电脑


例如攒了一台性能吊炸天的电脑,你不需要去打开主板、打开cpu、打开内存、打开硬盘、打开...只要按一个开关机按钮即可,这就是外观模式(别名门面模式)生活中的应用。




装家电,电子设备充电


例如买了家电,装修工人不管你要装什么电器,两项、三项的插头都装好了,接口做好了。电器出厂的时候也是有统一标准的,实现这个接口,买回来就可以用啦,这就是依赖倒置原则在生活中的应用。继续来说用电情况,国内标准民用是交流电220V电压即AC220V,笔记本和手机的充电器里面会有变压器,把交流电220V转换成直流电5V,否则笔记本和手机直接就挂了..必须转换。而这个又是适配器模式在生活中的应用。


买煎饼



例如有时候上班晚了,在单位楼下买煎饼,去单位茶水间吃早餐。边吃边思考...emmm....对于买卖煎饼这件事,一般呢加一个蛋,也有加两个蛋,也有土豪加十个蛋;再加一些蔬菜、烤肠之类的,把这个简单的生活场景抽象到业务模型变成了,UML如图




那对于这种设计,首先是Battercake煎饼这个类做为父类。


BattercakeWithEgg做为加了一个鸡蛋的煎饼呢,继承了Battercake煎饼类。BattercakeWithEggSausage加了一个鸡蛋,一根烤肠的煎饼呢又继承了BattercakeWithEgg带一个鸡蛋的煎饼类,cost方法调用父类的super.cost来增加金额。这种设计可否满足大众不同的口味扩展呢,当然是不能的,如果土豪来买带有十个鸡蛋的煎饼,我们还要创建一个类,名字为BattercakeWithTenEgg(暂不考虑英文复数)。 那我们这个程序设计的扩展性就比较差了,大众口味万千,煎饼子类爆炸。后期根本不可控。



饰者模式



而通过设计模式的装饰者呢?我们先看一下UML



ABattercake aBattercake; 
aBattercake = new Battercake(); 
aBattercake = new EggDecorator(aBattercake); 
aBattercake = new EggDecorator(aBattercake); 
aBattercake = new SausageDecorator(aBattercake); 
System.out.println(aBattercake.getDesc()+" 销售价格:"+aBattercake.cost());


通过装饰者的封装大大提高做各种style煎饼的扩展性。那这是生活中设计模式一个简单的例子。





JDK
源码装饰者的使用


那在JDK源码及开源框架层面,如图




开源框架源码



这个图就表达了,mybatis框架当中关于cache里的装饰者模式和建造者模式结合的使用。换个视角,来看开源框架源码,有趣许多。



享词汇


最后还想表达一下共享词汇在日常学习工作中的威力,我们在和同事交流的时候,不可能去很详细的描述说这个场景我用什么类继承了什么类,然后用什么类实现了什么接口,在另外一个类里面又组合了这个接口,这么说估计说一半的话估计就要被打断,我们直接上小黑板画UML吧,嘿嘿,如果你说在A的抽象类和B的接口之间,通过桥接模式让他们这两块可以独立扩展。ok,表达的清晰加愉快,省去好多时间。作为工程师一定要表现出工程师professional的一面。



试抽象


还有就是可以尝试去抽象一下生活中的事物,例如,买煎饼、办理不同银行的不同种类银行卡(桥接模式的应用)等等,但是也别走火入魔,看到什么都想抽象...最简单的方式:“网购买个鞭子,然后去动物园,找到一头大象,然后开始抽象”O(∩_∩)O哈哈~。






合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。共勉!




今天我又给大家带来了一门《java设计模式精讲 Debug 方式+内存分析》,感兴趣的可以点击下图,了解详情 ^_^


▽ 点击下图,即可查看




近期热门阅读





 
慕课网 更多文章 我是怎么把一个项目带崩的 “职业程序员”不必那么“职业” 作为50 岁的开发者,面对被裁的命运,我如何绝地求生? @程序员,面试必懂的套路,看完整个人通透多了 从“写好代码”到“设计代码”,设计模式是必经之路
猜您喜欢 BadaCache 简介 分类中数据不平衡问题的解决经验 “智造”转型:IBM协助福耀玻璃抢占市场先机 记录2016老罗锤子发布会印象深刻的几点 下一代 Android 取的名字是棉花糖(Android Marshmallow)