无极's profile无极空间PhotosBlogLists Tools Help

无极

Interests
No list items have been added yet.
No list items have been added yet.
November 22

一切皆为虚幻    不可说  色即是空,空即是色   人生在世如身处荆棘之中,心不动,人不妄动,不动则不伤;如心动则人妄动,伤其身痛其骨,于是体会到世间诸般痛苦 一花一世界,一叶一如来  前生500次的回眸才换得今生的一次擦肩而过   大悲无泪,大悟无言,大笑无声  苦海无边,回头是岸。放下屠刀,立地成佛 菩提本无树,明镜亦非台,本来无一物,何处惹尘埃  你不入地狱,谁入地狱?
November 15

靠自己

  小蜗牛问妈妈:为什么我们从生下来,就要背负这个又硬又重的壳呢?  
  妈妈:因为我们的身体没有骨骼的支撑,只能爬,又爬不快。所以要这个壳的保护!  
  小蜗牛:毛虫姊姊没有骨头,也爬不快,为什么她却不用背这个又硬又重的壳呢?  
  妈妈:因为毛虫姊姊能变成蝴蝶,天空会保护她啊。  
  小蜗牛:可是蚯蚓弟弟也没骨头爬不快,也不会变成蝴蝶他什么不背这个又硬又重的壳呢?  
  妈妈:因为蚯蚓弟弟会钻土, 大地会保护他啊。  
  小蜗牛哭了起来:我们好可怜,天空不保护,大地也不保护。  
  蜗牛妈妈安慰他:所以我们有壳啊!我们不靠天,也不靠地,我们靠自己。
November 08

靠自己

     小蜗牛问妈妈:为什么我们从生下来,就要背负这个又硬又重的壳呢?  
  妈妈:因为我们的身体没有骨骼的支撑,只能爬,又爬不快。所以要这个壳的保护!  
  小蜗牛:毛虫姊姊没有骨头,也爬不快,为什么她却不用背这个又硬又重的壳呢?  
  妈妈:因为毛虫姊姊能变成蝴蝶,天空会保护她啊。  
  小蜗牛:可是蚯蚓弟弟也没骨头爬不快,也不会变成蝴蝶他什么不背这个又硬又重的壳呢?  
  妈妈:因为蚯蚓弟弟会钻土, 大地会保护他啊。  
  小蜗牛哭了起来:我们好可怜,天空不保护,大地也不保护。  
  蜗牛妈妈安慰他:所以我们有壳啊!我们不靠天,也不靠地,我们靠自己
September 24

知固而不知革,物失其则;知革而不知固,物失其均。

第四章 -闭原则(OCP

正如牛顿三大定律在经典力学中的位置一样,“开-闭”原则(Open-Closed Principle)是面向对象的可复用设计(Object Oriented DesignOOD)的基石。

4.1 什么是“开-闭”原则

1.         定义:一个软件实体应当对扩展开放,对修改关闭。

           Software entities should be open for extension,but closed for modification.

        即在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。

2.         满足“开-闭”原则的系统的优点

a)         通过扩展已有的软件系统,可以提供新的行为,以满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性。

b)        已有的软件模块,特别是最重要的抽象层模块不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。

3.         这样的系统同时满足了可复用性与可维护性。

4.2 怎样做到“开-闭”原则

西游记中的例子:玉帝招安美猴王

在不破坏天庭秩序的前提下,用招安封官的方法,将美猴王这个新的需求,容纳至旧有系统之下,维持了稳定性。(LY注:奇怪呀,玉皇大帝和文武仙卿怎么会是聚合关系呢?聚合关系不是整体和部分吗?看此书后文这样用很多,也许将三者混用了吧。毕竟这三者语法上没有区别。

关键在于不允许破坏现有的天庭秩序,但是允许将美猴王加入现有秩序中,从而扩展此秩序。

在面向对象中,不允许更改的是系统的抽象层,而允许扩展的是系统的实现层。

《太玄》论“固革”

西汉杨雄《太玄》:“知固而不知革,物失其则;知革而不知固,物失其均。”

一个系统对修改关闭(LY注:不允许修改),就是“固”;系统对扩展开放,就是“革”。一个系统不可扩展,就会“物失其则”,或者说系统失去使用价值;而一个系统动辄需要修改,便会“物失其均”,也就是失去重心。

LY注:这可不是水浒传里的杨雄。揚雄(西元前53~西元18),西漢學者、辭賦家。姓氏“揚”,或作“楊”。字子雲。蜀郡成都(今四川成都)人。少時好學,博覽多識,酷好辭賦。口吃,不善言談,而好深思。家貧,不慕富貴。40歲後,始游京師。大司馬王音召為門下史,推薦為待詔。後經蜀人楊莊的引薦,被喜愛辭賦的成帝召入宮廷,侍從祭祀游獵,任給事黃門郎。他的官職一直很低微,曆成、哀、平“三世不徙官”。王莽稱帝後,揚雄校書於天祿閣。後受他人牽累,即將被捕,於是墜閣自殺,未死。後召為大夫。揚雄一生悉心著述,除辭賦外,又仿《論語》作《法言》,仿《周易》作《太玄》,表述他對社會、政治、哲學等方面的思想,在思想史上有一定價值。另有語言學著作《方言》等。《隋書·經籍志》有《揚雄集》5,已散佚。明代張溥輯有《揚侍郎集》,收入《漢魏六朝百三家集》。今四川有西蜀子云杨雄墓。)

抽象化是关键

解决问题关键在于抽象化,定义一个一劳永逸的抽象设计,允许无穷尽的行为在实现层被实现。(LY注:抽象作为面向对象的第一个核心本质,它的地位太重要了。对一个事物抽象,实质上是在概括归纳总结它的本质。抽象让我们抓住最最重要的东西,从更高一层去思考。这降低了思考的复杂度,我们不用同时考虑那么多的东西。PS:抽象让我们看到事物的本质,而封装让我们除了本质之外,什么细节都看不到。

Java中,通过抽象类和Java接口,规定了具体类的特征作为抽象层,相对稳定,不需更改,从而满足“对修改关闭”;而从抽象类导出的具体类可以改变系统的行为,从而满足“对扩展开放”。

对可变性的封装原则

“开-闭”原则也就是“对可变性的封装原则”(Principle of Encapsulation of Variation EVP)。即找到一个系统的可变因素,将之封装起来。

考虑你的设计中什么可能会发生变化,而不是什么会导致设计改变。LY注:这个地方是说要预见到变化的部分吗?而不是出现了变化才考虑改变。我这样理解的,不知是否确切。)

“对可变性的封装原则”意味着:

a)         一种可变性不应当散落在代码的许多角落,而应当被封装到一个对象里面。同一可变性的不同表象意味着同一个继承等级结构中的具体子类。因此,此处可以期待继承关系的出现。继承是封装变化的方法,而不仅仅是从一般的对象生成特殊的对象。

b)        一种可变性不应当与另一种可变性混合在一起。作者认为类图的继承结构如果超过两层,很可能意味着两种不同的可变性混合在了一起。

使用“可变性封装原则”来进行设计可以使系统遵守“开-闭”原则。

即使无法百分之百的做到“开-闭”原则,但朝这个方向努力,可以显著改善一个系统的结构。

4.3 与其他设计原则的关系

其他设计原则是实现“开-闭”原则的手段和工具。

1、 里氏代换原则(Liskov

       任何基类可以出现的地方,子类一定可以出现。

       实现“开-闭”原则的关键步骤是抽象化。基类与子类之间的继承关系就是抽象化的体现。因此里氏代换原则是对实现抽象化的具体步骤的规范。

    违反里氏代换原则意味着违反了“开-闭”原则,反之未必。

2、 依赖倒转原则

       要依赖于抽象,不要依赖于实现。

       “开-闭”原则与依赖倒转原则是目标和手段的关系。

3、  合成/聚合复用原则LY注:或者叫组合/聚合复用原则

       要尽量使用合成/聚合,而不是继承来达到复用的目的。(LY注:关于这一论断,许多著作中有所阐述。我想也许是因为人们太喜欢继承了,尤其是对OO稀里糊涂的时候,使用继承让人们自我感觉良好,好像成了OO专家。当满足里氏原则的时候(同样也满足“is a”关系),使用继承会有助于对问题的理解,降低复杂度。其他情况下,使用继承是一种滥用,而滥用继承会增加系统的复杂度和构建的难度。组合/聚合则使系统灵活

       设计师们应首先使用组合/聚合,其次才考虑继承。而使用继承时,要严格遵循里氏代换原则。

4、 迪米特法则

       一个软件实体应当与尽可能少的其他实体发生相互作用。

       这样,当一个模块修改时,就会尽量少的影响其他的模块。扩展会相对容易。

       这是对软件实体之间通信的限制。它要求限制软件实体之间通信的宽度和深度。

5、 接口隔离原则

       应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。

   这也是对软件实体之间通信的限制。但它限制的只是通信的宽度,就是说通信要尽可能的窄。

       遵循迪米特和接口隔离法则,会使一个软件系统功能扩展时,修改的压力不会传到别的对象那里。

4.4 策略模式对“开-闭”原则的支持

策略模式:如果有一组算法,那么就将每个算法封装起来,使得它们可以互换。

这就是通过对可变性的封装,达到“开-闭”原则的例子。

LY注:此处可变的是实际使用的算法,而通过对多个算法的抽象和封装,抽象算法是相对稳定不变的。扩展时可以方便地加入新的算法,而不必修改已有的系统。

4.5 在其他设计模式中的体现

“对可变性的封装”实际上是设计模式的主题。换句话说,所有的设计模式都是对不同的可变性的封装,从而使系统在不同的角度上达到“开-闭”原则的要求。

1、  简单工厂模式(Simple Factory

       加入新产品时,工厂角色要变化,但是消费者可以避免修改。(LY注:简单工厂模式中客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。比如一个园丁负责所有的水果

2、  工厂方法模式(Factory Method

       定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类型实例化延迟到它的子类。(LY注:核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。比如有许多个园丁,每人负责一种水果。

       当需要加入新产品类型时,不必修改已有的代码,只需要再加入一个相应的新的具体工厂类就可以了。

    对于增加新产品类,这个系统完全支持“开-闭”原则。

3、  抽象工厂模式(Abstract Factory

       提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。LY注:这句话很晦涩,我想应该是指对产品对象家族的封装吧

       抽象工厂模式封装了产品对象家族的可变化性,从而一方面可以使系统动态地决定将哪一个产品族实例化,另一方面可以在新的产品对象引进到已有的系统中时不必修改已有的系统。在产品对象家族发生变化时,此设计可维持“开-闭”原则。

4、  建造模式(Builder

       产品有不同的组成部分作为零件,这些零件可能是对象,也有可能不是对象,它们通常又叫做产品的内部表象。不同的产品可以有不同的内部表象,也就是不同的零件。使用建造模式可以使客户端不知道所生成的产品对象有哪些零件,每个产品对应零件有何不同,是怎么建造的,以及怎样组成产品。对内部表象来说,满足“开-闭”原则。

   它把产品的结构和构造过程对客户端隐藏起来了。把对建造过程进行指挥的责任和具体建造者零件的责任分割开来,达到责任划分和封装的目的。LY注:曾和装饰类混淆过,在此重申一下。一个是构造,而另一个是动态扩展。建造模式:将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。装饰模式装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。

5、  桥梁模式(Bridge

       抽象部分与实现部分分离,使它们可以独立地变化。

LY注:我最喜欢的模式之一,简单又灵活。很难不让人喜欢上它。J

6、  门面模式(FAÇADE 外观模式)

       为子系统中的一组接口提供一个一致的界面。多用于为一个复杂子系统产生一个简单接口。

       使用门面模式可以改变系统内部功能而不会影响到客户端。

7、  调停者模式(Mediator 中介者模式)

       使用一个调停者对象协调各个同事对象的相互作用。而这些同事对象不再发生直接的相互作用。当有新的同事加入进来的时候,已有的同事对象不会受到影响,而调停者对象本身却需要修改。换言之,调停者以一种不完美的方式支持“开-闭”原则。

8、  访问者模式(Visitor

       访问者模式将数据结构和作用于结构上的操作分开,使得操作可以相对自由的变化。访问者模式使得在节点中加入新的方法很容易,只需要在一个新的访问者类中加入此方法就可以了,但是访问者模式不能很好地处理增加新的节点的情况。

这是种不完全的可扩展性设计:方法聚合的可扩展性和类集合的不可扩展性。LY注:Visitor适用于那些类相对稳定的情况下。如果类经常改变,那么在类的定义中定义这些操作更好。

9、  迭代子模式(ITERATOR

       迭代子模式将访问聚集元素的逻辑封装起来,并使它独立于聚集对象的封装。这使聚合对象存储和迭代相对独立。可以在不修改使用迭代的客户端的情况下,对聚集对象的内部结构进行功能扩展。

 

学习设计模式要注意每个模式可以支持什么样的变化,以及为做到这一点所付出的代价。是怎样支持“开-闭”原则的。

4.6 一个重构做法的讨论

“将条件转移语句改写成为多态性”,是广为流转的代码重构做法。但这种方法未必总是正确。

1、  条件语句常意味着某种可变性。将这种可变性用多态性代替,就意味着将这种可变性封装起来。

2、  注意,条件语句本身并不是错误的。而且,使用多态性代替条件意味着大量的类被创建出来。

3、  要从“开-闭”原则出发来考虑需要重构。如果有可变性需要封装,那么重构。反之改写为多态是一种浪费。

问答题

Java.util.calendar是否符合“开-闭”原则?答:Java.util.calendar不符合“开-闭”原则。因为它对星期的运算只适用于公历。如果要加入中国阴历,必须要做大量修改才能适用。(LY注:阴历的是十天一周?作者指的是旬吗?此处暂存疑。

September 22

领导请爹吃饭闹出来的笑话

 

领导调到一个新地方不久,在村里种地的老爹就急急忙忙地来看望。领导中午正有一个应酬,不能陪老爹吃饭,怕老人家生气,就给治下一家大酒店的老板打了个电话,嘱咐帮助招呼好一个客人。

老板问:“领导,是什么关系呀?我好根据情况安排。”

领导蛮幽默的,卖关子说:“特殊关系啊。”

老板打破沙锅问到底:“怎么个特殊法嘛?”

领导故作神秘:“别问那么多!反正我和他儿媳妇关系相当好。

老板嘿嘿一笑:“哦!小的明白!请领导放心!”

老板立即安排车子把老汉接到酒店最豪华的包间,并亲自陪酒。

老汉喝了几杯,见老板和服务员殷勤备至,就找到感觉地问:“你们知道俺和你们领导的关系?”

“知道!知道!”

老汉一抹嘴:“那老板说说俺俩是甚关系!”

“这个……”

老汉砰地一墩酒盅:“怕甚了!这里又没甚外人!”

“……领导和您儿媳妇关系不赖……”

“看看!你们只知道他和俺儿媳妇关系不赖,就不知道俺和他妈的关系更不赖?”

 老板立即把两个服务员拉到门外:“今天这疯老汉说的,对谁也不能讲!”
 
石榴  
Photo 1 of 1