本读书笔记由Markdown编辑器编辑完成。
所有编程初学者都会有这样的问题,就是碰到问题就直觉地用计算机能够理解的逻辑来描述和表达待解决的问题及具体的求解过程。这其实是用计算机的方式去思考。
如果仅仅按照计算机的方式去思考,那么这样写出的程序只能实现当前的需求,程序不容易维护,不容易扩展,更不容易复用。因此,也达不到高质量代码的要求。
曹操的《长歌行》
1. 喝酒唱歌,人生真爽……
2. 对酒当歌,人生真爽……
3. 对酒当歌,人生几何?
“活字印刷术与编程”:
第一,要改,只需更改要改的文字,此为可维护;
第二,这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;
第三,此诗若要加字,只需另刻字加入即可,这是可扩展;
第四,字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。
通过面向对象的分析设计编程思想,开始考虑通过封装、继承、多态把程序的耦合度降低。
中国古代的四大发明,另三种应该都是科技的进步,伟大的创造或发明。而唯有活字印刷,实在是思想的成功,面向对象的胜利。
业务的封装:就是让业务逻辑与界面逻辑分开,让它们之间的耦合度下降。只有分离开,才可以达到容易维护或扩展。
紧耦合 VS 松耦合
简单工厂模式(Simple Factory Pattern)
http://design-patterns.readthedocs.org/zh_CN/latest/creational_patterns/simple_factory.html
模式定义——又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
模式结构:
简单工厂模式包含如下角色:
(1)Factory:工厂角色
工厂角色负责实现创建所有实例的内部逻辑;
(2)Product:抽象产品角色
抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口;
(3)ConcreteProduct:具体产品角色
具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
UML类图:
类图分三层,第一层显示类的名称,如果是抽象类,则就用斜体显示;
第二层是类的特性,通常就是字段和属性;
第三层是类的操作,通常是方法或行为。注意前面的符号,“+”表示public, “-”表示private, “#”表示protected.
聚合表示一种弱的“拥有”关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分。
合成(Composition,也有翻译成’组合’的)是一种强的‘拥有’关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。
依赖关系
关联关系
继承关系
编程是一门技术,更加是一门艺术,不能只满足于写完代码运行结果正确就完事,时常考虑如何让代码更加简练,更加容易维护,容易扩展和复用,只有这样才可以真正得到提高。
简单工厂实现:
面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。
商场的促销活动中,打一折和打九折只是形式的不同,抽象分析出来,所有的打折算法都是一样的,所以打折算法应该是一个类。
简单的工厂模式虽然也能解决这个问题,但这个模式只是解决对象的建问题,而且由于工厂本身包括了所有的收费方式,商场是可能经常性地更改打折额度和返利额度,每次维护或扩展收费方式都要改动这个工厂,以致代码需要重新编译部署,这真的是很糟糕的处理方式。
面对算法的时常变动,应该有更好的办法。
策略模式(Strategy Pattern)
策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
p53.
//简单工厂模式的用法
CashSuper csuper = CashFactory.createCashAccept(cbxType.SelectedItem.ToString());
//策略模式与简单工厂结合的用法
CashContext csuper = new CashContext(cbxType.SelectedItem.ToString());
通过对以上两段描述,简单工厂模式我需要让客户端认识两个类,CashSuper和CashFactory,而策略模式与简单工厂结合的用法,客户端就只需要认识一个类CashContext就可以了。耦合度更加降低。
策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合(DPE)。
策略模式另外的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
高手和菜鸟的区别就是高手可以花同样的代价获得最大的收益或者说做同样的事花做小的代价。
单一职责原则——就一个类而言,应该仅有一个引起它变化的原因。
如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。事实上,你完全可以找出哪些是界面,哪些是游戏逻辑,然后进行分离。
方块的可移动的游戏区域,可以设计为一个二维整型数组用来表示坐标。那么整个方块的移动其实就是数组的下标变化。那么,所谓游戏逻辑,不过就是数组的每一项值变化的问题,下落、旋转、碰撞判断、移动、堆积这些都是在做数组具体项的值的变化。而界面表示逻辑,不过是根据数组的数据进行绘出和擦除。
软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离。要去判断是否应该分离出类来,那就是如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责,就应该考虑类的职责分离。
界面的变化是和游戏本身没有关系的,界面是容易变化的,而游戏逻辑是不太容易变化的,将它们分离开有利于界面的改动。
整合当然是一种很好的思想。比如Google最初的理想就是将一切的需求都整合到一个文本框里提交,用干净的页面来吸引用户,导致互联网的一场变革。但现在分类信息、垂直搜索又开始流行,这却是单一职责的思想体现。
在编程时,要在类的职责分离上多思考,做到单一职责,这样的代码才是真正的易维护、易扩展、易复用、灵活多样。
开放-封闭原则,是说软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。
这个原则其实是有两个特征:
一个是说“对于扩展是开放的(Open for extension)”;
一个是说“对于更改是封闭的(Close for modification)”。
怎样的设计才能面对需求的改变却可以保持相对稳定,从而使得系统可以在第一个版本以后不断推出新的版本呢?
开放-封闭原则的意思就是说,你设计的时候,时刻要考虑,尽量让这个类是足够好,写好了就不要去修改了,如果新需求来,我们增加一些类就完事了,原来的代码能不动则不动。
在我们最初编写代码时,假设变化不会发生。当变化发生时,我们就创建抽象来隔离以后发生的同类变化。面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。这就是“开放-封闭原则”的精神所在。
开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象。然而,对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。
依赖倒转原则:
面向对象的四大好处——可维护、可扩展、可复用和灵活性好。
PC电脑里叫易插拔,面向对象里这种关系叫——强内聚、松耦合。
接口:CPU只需要把接口定义好,内部再复杂也不让外界知道,而主板只需要预留与CPU针脚的插槽就可以了。
依赖倒转原则(依赖倒置原则)——抽象不应该依赖细节,细节应该依赖于抽象。说白了,就是要针对接口编程,不要对实现编程。无论主板、CPU、内存、硬盘都是在针对接口设计的。
依赖倒置原则:
A、高层模块不应该依赖低层模块。两个都应该依赖抽象;
B、抽象不应该依赖细节。细节应该依赖抽象。
里氏代换原则(LSP):一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它觉察不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化。简单地说,子类型必须能够替换掉它们的父类型。
正因为有了这个原则,使得继承复用成为了可能,只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。
依赖倒转其实就是谁也不要依靠谁,除了约定的接口,大家都可以灵活自如。还好,她没有问我如何修收音机,收音机里都是些电阻、三极管,电路板等东西,全都焊接在一起,无法进行拆分。
收音机:收音机就是典型的耦合过度,只要收音机出故障,不管是没有声音、不能调频,还是有杂音,反正都很难修理,不懂的人根本没法修,因为任何问题都可能涉及其他部件,各个部件相互依赖,难以维护。
非常复杂的PC电脑可以修,反而相对简单的收音机不能修,这其实就说明了很大的问题。
依赖倒转其实可以说是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象的设计,反之那就是过程化的设计了。
很多银行目前还是纯C语言的面向过程开发,非常不灵活,维护成本是很高昂的。但是,那也是没办法的,银行系统不是说换就换的。所以现在大力鼓励年轻人学设计模式,直接面向对象的设计和编程,从大的方向上讲,这是国家大力发展生产力的很大保障呀。