NOTE:Design Pattern

2007-6-11

 

 

1.什么是模式:一个模式描述了在我们周围[不断重复]发生的问题,以及该题解决方案的核心

 

 

2007-7-9
________________________________________________________________________________________________________________________

软件系统中,一个模块设计的好不好一个非常重要的标志就是:该模块在多大的程度上将自己的内部数据与他的实现细节隐藏起来.
一个设计得好的模块可以将它的所有的实现隐藏起,彻底地将提供给外界的API和自己的实现分隔开来,这样一来,模块与模块之间就
可以仅仅的通过彼此的API进行通信,而不理会模块的内部实现细节!这就是我们所说的封装!是软件设计的一个基本的原则!

 

 

2007-7-10
_________________________________________________________________________________________________________________________
challenge 2.1
write down three differences between abstract classes and interfaces in java?

解答:接口和抽象类的不同主要表现在以下几个方面:

1.首先我们第一时间会想到的是一个类可以实现多个接口但却只能继承一个父类,C++程序员的说法就是Java中的接口是用来实现多继承的.
 (不过这种说法听起好像有些别扭)

2.抽象类较之接口的一个最大的优势(也可能是唯一的优势了)就是当我们在一个抽象类中定义并实现了一个方法时,所有继承它的子类都将
直接拥有这个方法的实现.

3.接口不提供任何实现,而抽象类则可以为某个或某些方法提供一种默认的实现.这一不同的另一种表述就是:接口的所有的方法的都是抽象
方法,而抽象类的方法可以是非抽象的(也就是提供一个默认的实现)

4.抽象类可以声明并使用字段(field),但是接口则不可以,它只能定义static final型的数据.(另外多说一点的是:当我们在接口中定义任何
数据字段和方法时,不管我们是否加入相应的修饰符,所有字段都将自动定义为static final型,所有方法都被定义为public abstract类型.

5.基于3.抽象类可以定义自己的构造器,所然它不能被实例化.而接口则完全不可以定义构造器,因为它是一种纯的抽象,不应提供任何实现

 

 

2007-7-12
_______________________________________________________________________________________________________________________

关于Adapter模式的小结:

1.什么情况下使用适配器模式

  当我们在编程时遇到如下场景时:一个客户端声明要使用一组服务,这组服务由一个接口来表达,而我们现在可能会有一个已经存在的有用的类,它可以提供客户端所期望的这些服务,但是这个类并没有实现那个接口,这个时候,我们可以构建一个新的类,它在实现了接口的同时,又继承了那个已经存在的类.这个类在实现接口声明方法时调用其父类(也就是那个已经存在的可用的类)的相应方法从而实现了接口所承诺的服务.我们说我们构造的这个新类就是一个适配器类,它很好完成将某种需求和一个已经存在的类之间的适配工作.
  上面提到的是类适配器,当客户端使用的一个具体的类而不是接口时,我们就无法使用这种适配器了,原因很简单:一个类不能同时继承两个父类.这个时候我们将会使用另一种形式的适配器,那就是对象适配器.
  对象适配器的适用情况上面已经说了,那就是客户端使用了一个具体的类,这个具体类可能提供的一种默认服务或是特定的服务,现在我们又有了一个现成的类,这个类提供的是另外一种特定的服务,当客户端需要的是这种服务时,我们就可以使用对象适配器的,这种适配器的工作原理是继承客户端使用的具体类,并关联现成类的一个对象,在类内部重写父类的方法,调用现成类对象的方法来实现.从而完成了适配工作.
  关于对象适配器的一个很好的例子就是适配JTable的AbstractTalbeModel类,实现特定类型数据在表格中的显示.但是我发现在这个例子对对象适配器的运用还不是很充分,也就是说没有很好的体现出对象适配器的普遍操作.因为在这个例子里,谈不上将特定的对象(就是要求显示数据的对象)适配给AbstractTalbeModel类,在我们的适配器里所做的操作无非就是把要求显示数据的对象的属性一一告知适配器而已.
  关于上面提及的类子参见DesiagnPattern工程
  最的再次强调的是要注意类适配器和对象适配器的适用场景,一个是将一个类适配给接口,一个是将一个对象的实例适配给一个类.
要补充说明的是:对象适配器会使系统/模块变得脆弱.原因自己想想吧.
   
  忘记介绍一种特殊的适配器了:缺省适配器.也就是大家所熟知的WindowAdapter,MouseAdapter,KeyAdaptoer等.这种适配器的特殊之处就在于它只实现了目标接口,却没有一个现成的类以供适配.这种实现方法看起来有些古怪,使用上面的适配器原则进行解译也不好说.但是这种设计是有目的的,它的作用就是为接口提供一个什么都没有做的默认实现,这样需要实现原来接口的类只需要继承这个适配器,并重写用到的方法就可以了,而不必实现原有接口的所有方法.
  基于上述分析我们可以确定:1.缺省适配器一定是一个抽象类,因为它所提供的方法没有任何实现意义,实例化后没有意义
               2.但是它的方法都不是抽象方法,而是一个个的真实方法,因为它必须提供一个默认实现,虽然这个实现什么也没做.

 

 

2007-7-15
________________________________________________________________________________________________________________________
1.关于facade门面模式

在一个复杂的子系统中,如果用户想要得到他想要服务,很有可能会使用到子系统中的多个类,并进行一些复杂的操作才能达到目的.在这种情况下我们可以提供一个门面类,把客户端和子系统的内部复杂性分离开来,使得用户只与门面类找交道,避免了直接访问复杂的子系统.面门类所起到的作用就是将用户的请求分派到子系统中,通过调用子系统的相关组件来完成用户请求,返回给用户所请求的服务.
  从门面模式的适用场景可认看来,门面模式目的并不在于要向子系统添加什么新的功能,它的功能在于简化子系统的使用,使得客户端更加方便的得到他想的服务.

2.偶然想到的一个问题:关于Web开发的三层结构和迪米特法则
三层结构:web层-业务层-数据访问层.迪米特法则:只与你直接的朋友们通信
分层原则告诉我们层与层之间要尽量松耦合,每一层要相对独立,每一层都有自己的数据结构(如DAO层的PO,Web层的ActionForm等),当层与层之间需要数据通信的时候,只能在彼此相临的层之间进行数据的传送,而绝不允许出现ActionForm跑到业务层,或是DAO层的情况.呵呵,在这一刻鲜明地体现了迪米特法则的要求.只与你直接的朋友们通信!不要和陌生人说话!(呵呵,后面这句我自己加的)

3.门面模式与迪米特法则
迪米特法则除了要求:只与最近的朋友通信之外还强调通信要尽可能的少.我们来看:门面将原本客户端要访问的复杂子系统之间的多个类转变成客户端只访问一个门面类即可,这是一种以代码重构形式实现迪米特法则要求的模式.

 

 

2007-7-16
_______________________________________________________________________________________________________________

1.关于UML中的依赖关系:
依赖关系的例子包括:一个类使用另一个类的某个对象作为参数;一个类访问另一个类的某个全局对象;一个
类调用另一个类的某个类属操作。在所有这些情况中,都有从一个类到另一个类的依赖存在,即使
在这两个类之间并没有明显的关联关系。再一次声明,在被依赖类内进行的修改将会影响依赖类。
2.关于UML中关联关系:
关联关系可以大致的分为:一般关联/聚合/组成这三种,首先要明确的是这三种关系只是语义上的区分,不能通过java的语法对三种关系进行区分.关联(一般关联)是指关联双方地位上平等.而聚合是一种整体与部分的关系.这种关系表现为:一个类由另个的组成而来,但是部分类是可以独立存在的.比如:汽车类,可能由轮胎类组成.而轮胎类是可以脱离汽车类独立存在的.而组成关系则是一种更强的关联,它也是一种整合和部分的关系,但是它强调的是关联的双方(整体与部分)是一个在机整体,部分不能脱离整体而独立存在.比如说:公司类由部门类组成,但是部门类不能独立于公司类单独存在.
  还是再强调一下:一般关联/聚合/组成这三种关系是体现的上类与类在语义上关系.是根据它们各自代表的概念来确定是何种关联关系的.从java语法上看,他们都是以成员变量的形式表现出来的,但是却不能中区分出是它们是何种关联.这得从对象体表的意义来确定他们之间的关系.

 

 

2007-7-18
_______________________________________________________________________________________________________________

组成模式小节:

1.什么是组成模式
组成模式是一种把具有共同特征的多个个体组件(或合成组件)组装成一个与其个体组件具有相同特征合成组件的设计方法

2.组成模式的适用场景
从组成模式的设计的概念上可以知道:在一个子系统里可能存在一些个体组件和一些由多个个体组件和合成组件组成的合成组件时,如果客户端需要将个体组件和合成组件一致对待时,就可以采用组成模式.这种一致对待是指从客户端角度不区分个体组件和合成组件,而是把它们一致视为"组件",对它们的调用将到得到一致的期望结果.比如说一台电脑是由显示器,机箱等组成的,而机箱又由主版/硬盘/各种扩展卡组成,我们说这些对我们客户来说都是"电脑配件",每种配件都有一个价格,我们可以方便的得到硬盘的价格,同样我们也应该能得到电脑的价格,这个价格应该由商家把各个配件的价值之各计算出来,再反馈给我们,对于我们客户而言,我们还是得到了电脑的价格,这个价格的等到方法是把各组件价格相加得到的.这个时候,我可以就可以采用组成模式来设计我们的电脑系统.

3.组成模式的关键点:
组成模式有几个值得特别注意的地方:一:不管是个体组件还是合成组件,它们对于客户端而言都将被一致对待,之所以能"一致对待"的关键是个体组件和合成组件它们都是组件,这明确地告知我们:实现组成模式的一个前提就是:所有组件应该实现同一个"Component"接口或是继承一个抽象类!以便它们有一个共同的"组件"身份.二:合成组合本身也是组件,所以它具有组件的一切特征,但同时它作为"合成"组件也就其不同之处,主要是:1.它应该持有一个数组,用于引用组成它的所有子组件!注意子组件不只是个体组合,也可以是合成组件! 2.合成组件应该提供对其子组件的操作方法:例如add,remove等方法!

4.关于组成模式中子组件操作方法的归属问题
这个问题就是说:子组件的操作方法是应该放到组件接口上还是应该加入到合成组件中?
对于这个问题的两种选择对应都两种类型的组成模式:
一种是安全的组合模式:即子组件操作方法只出现在合成组件中,而不出现在组件接口中
二种是透明的组合模式:即子组件操作方法直接出现在组件接口中,这样个休组件也会是具有这个方法,但是从意义上讲,它们是不应该有这些操作的,解决方法是只能给出一种平庸的实现,例如单纯的返回NULL.
以上两种形式,我更倾向于前者.后者的设计即不安全也不符合接口的原则!

 

 

2007-7-21
______________________________________________________________________________________________________________________

桥接模式小结:

  一般来说,桥接模式并不是一个使用率很高的模式,但是在适用它的场合,桥接模式的威力是非常大的.在学习这个模式之前有必要弄明白两个概念:类的抽象和实现.我们知道:一个类本身就代表了一个抽象的概念.尤其是当这个类是一个抽象类或者干脆就是一个接口的时候,它将表达一个更纯的抽象.但是我们不能只依靠抽象类和接口,为了能够使我们的类真正地对应到现实世界中的一个实体,我们需要对抽象类进行继承,针对每个抽象方法给出一种具体的实现,在一个类的层次结构中,所有处于下层的实现类都无一例外的在秉承了父类表达的抽象概念的同时,为这一抽象概念提供了一个具体的实现!(从这一点来理解我们也可以体会到继承和多态的作用就是把一个稳定而统一的抽象扩展成一组形式多样的实现)在从抽象概念到具体实现的过程中,我们是通过一层层的继承来实现的,在每一次继承过程中,我们都把一个抽象的概念"绑定"到了一个具体的实现上.这在大多数情况下是没有问题的,但是当一个实现类的实现方式不止一种的时候的,问题就会很快的暴露出来.例如:我们要设计一个模拟飞机的系统,飞机接口向下派生客用机和货用机,当设计具体的客用机机时,由于不同公司设计的飞机有很大的不同,我们可能发将客用机派生成空客客用机和波音客用机,同样,货用机也面临着同样的问题,我们来看:就客用机而言如果我们忽略它的生产公司而向下进一步设计时,我们可能会设计出:私人小型客机/大型商用客机等等,但是困扰我们的问题再一次发生了,我们不得不根据不同的产生公司来设计出诸如空客私人小型客机/波音私人小型客机/空客大型商用客机/波音大型商用客机等等,而在货用机方面也面临同样的问题,我们的类因为不同的生产公司(实现方式)而出现了爆炸性的增长,而更糟糕的是当我们要引入第三第四家飞机制造商的时候,原有的类体系结构必须扩充而且要重新编译,然而当出现多家公司合作生产或是由一家飞机公司的子公司生产一种飞机的时候问题可能会更加糟糕.也就是当实现方式也在独立演化的时候,我将几乎无法组织起起我们类体系结构,我们原本设计的简明而清晰的抽象体系结构因为具体实现的问题而变得变得琐碎和臃肿.抽象和实现牢固地绑定在一起,使得它们无法独立的扩充/修改和复用,变动一个抽象会牵扯到所有的实现,而变动一个实现也会影响到所有的抽象.这就是问题的核心,而解决这一问题的关键就是要将抽象和实现进行分离,使得它们可以独立的演化.
  那么如何将抽象和实现进行分离,使得它们可以独立的演化呢?这就是"桥接"模式所要解决的问题."桥接"模式把实现抽离到一个单独的类体系结构中,使得它可以独立的进行演化,而我们的抽象只需要关连这个实现体系的上层接口,然后在定义这个抽象的具体实现时调用实现接口的相应方法就可以完美地解决我们之前所遇到的问题.
  驱动程序是应用Bridge模式最常见的实例.JDBC为例:简单地说:JDBC是用于执行SQL语句的应用编号接口,JDBC驱动程序就是实现该接口的类:数据库应用程序就是对数据库操作的抽象,它依赖于JDBC驱动程序:只要提供JDBC驱动驱动程序,数据库应用程序就可以操作任何数据库.JDBC这种架构将抽象与具体实现相分离,使得数据为应用程序和JDBC驱动程序能够独立地发展--这就是应用桥接模式所带来优势.

 

 

2007-7-24
__________________________________________________________________________________________________________________________

1.关于在一个类层次结构中是否要提供抽象类的问题
  当我们要设计一个类层次结构是,绝大多数情况下采用的套路是:在最上层设计一个接口,描述这个子系统或功能模块所应提供的各种服务,然后设计一个抽象类实现这个接口,对接口的要求的方法给出一种普遍的或是默认的实现(如果有这种普遍或是默认的实现时,否则就不予提供),再然后就是设计多个具体的实现类继承抽象类,并重写和添加一些自己的具体实现.
  但有的时候我们可能只提供一个接口,不提供抽象类,各个实现类直接实现接口声明的方法.
  那么我们应该如何适时地选择抽象类的使用呢?这当然要根据具体的情况做出相应的判断,这里有一些准则,自己总结的,可能不完全正确
1)我们对于抽象类的定位是给出一些基本的默认的实现,如果基于接口所描述的服务中可以给出一种通用的/默认的/基本的实现那么我们就可以添加上一个抽象类来实现这些服务
2)看整个类层次结构的规模,对于一个很小的(可能只有两三个类)的类层次结构,从简洁的角度出法,可以省去抽象类.
3)反向判定:先不写出抽象类,看看已实现的多个具体类中是否有一些相同的重复代码,如果有,就说明:我们应该把它们放到一个抽象基类里.

2.一点感悟:
  我们总是遵从这样一种设计准则:把我们的模块或是子系统尽可能的细化,进而产生出一系列功能单一,封装完好的类,然后通过它们之间的相互协作实现系统(模块)的功能.这样做的好处在于功能单一,封装完好的类具有很高的复用性,同时降低了系统的耦合度.但是这样做也会有一些代价的(副作用)那就是类的数量会明显增多,这对于维护对象间的一致性不利(此时考虑观察者模式)

 

 

2007-7-25
________________________________________________________________________________________________________________________

1.单态模式小结
  关于单态模式就不说太多了,这个模式可能是最为人所熟知和最为简单的一种设计模式了.也是因为如此它可能会被滥用.用记住一点是并不当只需要一个类的唯一对象时就一定要使用单态模式,单态的适用场景是:当我们需要为一个类仅提供一个唯一的实现并且为个实现提供一个全局的访问点时才会使用单态模式.
  单态的两种常用方式:有状态的单态类:这种类可能包含一到多个字段来表示某些属性,这种类可以当作状态类来使用.(我想过:其实一个全是static字段的类也是可以当来充当这个角色的,但是这种类有一个不中,那就是对于这些字段,它们一般都是public类型的,所有说对他们的读写没有限制,而且也不能能过getter和setter在读写添加一些业务逻辑.)第二种是无状态单态类.目前还没想好.
  最后要记住的一点是:如果使用"懒汉"式单态,一定要记得在getInstance方法前加上synchronize.

2.观察者模式
  对于这个模式看来也不用说太多了,因为Java直接提供了对这种模式的支持,那就是Obsersver接口(观察者)和Observerable类(被观察者)但是对于这种模式的适用场景还是要提一提的.当我们在设计过程中发现:如果有多个类同时依赖于一个类,并且这个并依赖的类发生变化时所有依赖于它的类都要做出相应的变化时,那么此时就要求我们使用观察都模式了.
  对于观察者模式我只想强调两个最容易被忽视的地方:1.千万不要忘记注册观察者.2.当被观察者的某些地方发生变化时,千万别忘了调用notifyObservers方法来通知所有的已注册的观察者,另外如果是继承了Observerable类的话,在调用该方法之前,切记要先setChanged!
  还要提一点,那就是当有我们的被观察者已经继承了某个类而无法再继承Observerable类时,可以让被观察者持有一个Observerable类的实例,在需要向它的观察者发出通知的地方,调用这个Observerable实例的notifyObservers方法就可以了,当然,如查需要传递参数的话,可以使用notifyObservers(Object o);方法,这个o完全可以是被观察者引用.

3.java对观察者模式的支持:
java为观察者模式提供了两套解决方案:一种是大家所熟知的Observer和Observerable,这个就不多提了,下面重点说说PropertyChangeSupport和ProtertyChangeListener.这两个类是java.beans包中的两个工具类,它不并不专门为观察者模式而设计,但是它却被GUI组件大规模的使用以实现观察者模式所有解决的问题,即当多个GUI的Component依赖于另一个Component时,这个Component的属性(状态)发生变化,将会使用上面两个类(确切地说是它们的子类)来通知所有对它存在依赖的Component.应该说这两个类与Observer和Observerable是有很多区别的,首先从它们的名字上可以看来,它两个类更关注于对象属性的变化,还有就是它们的之间对变化的信息也进行了封装,就是PropertyChangeEven对象.整合上感觉它们更加细致,而功能更为强大!

 

 

2007-7-26
________________________________________________________________________________________________________________________

一点感悟:
  现在面向对象的编程方法是如此之流行,它的众多优势是不言而喻的.笼统地讲,由于面向对象的基本单位是对象,这使得程序员可以很自然很方便的从现实世界中进行抽象,抽象出它在软件世界里的对应物,然后模拟它们在现实世界中的运行,从而构建起整个系统.当我们不厌其烦地在对"面向对象"技术歌功颂德的时候,我们也应该能够冷静地思考它的不足之外,因为在这个世界上没有什么东西是完美的.
  "面向对象"技术可能有很多不足或不尽完美之处,这里我只提两点:(呵呵,也是刚学来的.)
  一.现象世界中的事物都具有时间属性,它们的状态是连续地.但是我们程序中的对象却是静态的,离散地,无法得知它的过去.
  二.这个要说的真得是很要命!"面向对象"只针对事物进行抽象,得到软件世界中"对象",但是,在现实世界里,和对象一样具有重要意义的是它们之间的"关系"!而"面向对象"对此无能为力,不存在对对象间"关系"的抽象.

 

 

2007-7-26
______________________________________________________________________________________________________________________

对"责任"进行合理的划分是设计的重要任务也是构建良好系统的前提!

 

 

2007-7-30
______________________________________________________________________________________________________________________

关于observer模式和meadiator模式之间的差别

  两种模式的共同之处都是负责对象间(我们暂且把这种需要相互通信的对象称作:colleage吧)通信的.当一个colleage发的变化时,它应该通过某种方式把变化的信息传递给其他的colleage,而其他的colleage的接收到信息的时候也要做出相应的调整以适应新的变化.
  但是两种模式还是有着一定的差异的.这种差异主要表现在通信的复杂度上,更确切地说是通信者之间形成的通信网的复杂度上.
  observer模式的通信网是一种星形网,众多的对象只依赖于一个共同对像,它们只与这个共同对象进行信息交互.并且很重要的一个特征是:所有这些对象都以中心依赖对象"唯命是从",只有中心依赖对象发生变化,并通知了所有其他的对象,那些对象才会进行更新.这种模式完全排除了外围对象间需要通信的可能性.
  而meadiator模式则是针对上面提到的一种更为复杂的情形而设计的.那就是,众多的对象不是单单的只同一个对象进行通信,而是彼此之间互有通信,这样就形成了一张通信"网".这是一种十分糟糕的状况,每个对象都依赖于其他多个对象,一个对象发生了变化,会影响到所有依赖于他的多个对象,这样的系统对象之间高度耦合,几乎没有任何可复用性.对于这种状况我们必须要采取一定的措施把耦合度降至最低,这个时候就需要用到meadiator模式.meadiator模式的首要作用就是把原来网状的通信模型变换为星形的通信模型,使得原来彼此之间相互通信的对象从对多个通信对象的依赖转化成对一个对象的依赖.这个对象就是meadiator(中介者,调停者).而我们现在转换好的模形与观察者模式也极其的相似了,要说唯一的不同之处就是先会由一个colleage向meadiator发出变更通知,然后meadiator在内部实现所有相关colleage对象的同步更新,meadiator之所以能够这样做,是因为它持有所有colleage的引用!看啊,这也是很危险的,当colleage变得越来越多,关系变得越来越复杂的时候,这个meadiator将不可避免地变成一个怪物!但是他却换来了众多colleage的简洁与可能复用性!要知道:如果对象间的(真实的)依赖是不能消除的,我们只能通过某种方法来转化它以减弱这种依赖.
  说了这么多还没有谈到observer模式和meadiator模式之间的一个小关系,那就是在meadiator模式中,从colleage向meadiator发送消息时可以使用observer模式,把meadiator当作observer,所有的colleage视作subject.但是怎么都觉着有点别扭,因为这里subject成了多数而observer却只有一个了.我看还是使用meadiator传统的做法要好一些:在meaditor内部提供一个update(IColleage o)方法,根据是哪一个colleage来确定相应的变更动作.然后在所有的colleage发生变化需要通知其他对象的时候调用这个方法就可以了.
从这个角度的考虑我们就可以发现meadiator的一个目的就是对对象间的依赖关系以及依赖更新进行封装.

 

 

2007-7-31
________________________________________________________________________________________________________________________

  注意:在我的设计模式类程中的meadiator包并实现一个真正的调停者模式.这是因为我们无法改变Colleage对象(swing组件)的父类,
使得它们每人都拥有一个Meadiator成员变量.也就是说:GUI组件间的相互依赖关系不适合直接使用调停者模式
来解耦合!这合《设计模式》一书给出的例子不一样,在那个类子,作者是虚构了一个GUI类库,自己设计的图形组件
体系,在他们的设计中,可以在组件抽象基类加一个Meadiator成员变量,使得所有图形组件都只依赖于一个Meadiator
而我们这里使用的是成品的Swing库,不可能修改Componet类.当然,变通的方法还是有的,那就是让JFrame持有
一个meadiator对象,在组件变更的时候,也就是在响应函数内调用meadiator的update方法.当然这已经不再是标准的
调停者模式了,因为它把本该由Colleage负责的责任(向其他Colleage通知他已发生变化)推卸给了它的调用者.

 

 

2007-8-1
_______________________________________________________________________________________________________________________

关于flyweight模式

1.重要概念:一个对象的内部状态是指该状态不会虽外部环境的不同而发生变化。也就是说这种状态几乎总是immutable的!
而外部状态而会随外部环境的不同而不同。举个例子来说:在一个文本编辑器,如果对字符进行抽象的话,那么它的可能包括如下一些属性:
char c;int size;int color;int x,y;我们看这些属性中内部状态就是c,size,color,而外部状态就是x,y

 

 

2007-8-7
_________________________________________________________________________________________________________________________

1.如果我们设计出了工厂,那就是因为我们需要工厂,反过来说就是我们不希望客户端随意地创建产品实例,而是鼓励使用工厂来获得,这样的话我们可以采用一些措施来避免外界随意地获取产品,这里有两种方法可以选择:
1.)把产品类族和工厂类(族)放到一个独立的包中,设置产品类族的可见性(更确切的说是它的构造方法)为包内可见,设置工厂类(族)的可见性为public。这样一来可以保证包外的类不能直接创建产品类(因见见不到),而只能通过工厂来获得。
2.)一种更加“严格有效”的措施是把产品类设置成工厂类的私有内部类!这将彻底杜绝外界实例化产品类,但是这种方法显然不太适用于一个庞大的产品族,对于一些只有两三个产品类的情况倒是满不错的!java.util包中的Collections类就完全采用了这种方式!参见《Professional.Refactoring to Patterns》一书的6.3节,最后对Collections的讲解!

工厂方法模式的多种退化形式

1.当产品类族中只有一个具体类时,这是工厂方法会退化成静态工厂方法,即简单工厂方法。此时也将只有一个工厂类。典型的例子就是:Swing中的BorderFactory。当然,即使产品类族中不止有一个具体类时,也是可以使用简单工厂模式的,虽然这样做存在一些问题(简单的说就是不易扩展,难以复用,违反了开闭原则。)这个时候,为了能够创建多种类的实例一种常用的做法是:依靠指定的参数作为标志来创建对应的实例,如果作用类名来做为参数的话,可以考虑使用动态类加装机制(使用class.forName)来实现工厂方法。这样具有更好的复用性。

对于1的补充:在简单工厂模式中只有一个具体的工厂,而在工厂方法模式中有一个工厂层次结构。这克服了简单工厂模式的缺点,使得具体工厂和具体产品可以平行的发展,从而更加符合开闭原则。如果工厂方法模式中的工厂层次结构退化成为一个具体工厂,那么工厂方法模式就退化成了简单工厂模式。

2.将工厂和抽象产品两个参与者合并,让抽象产品来生产一个具体的产品。典型的例子就是DateFormat类和他的getDateInstance等方法。

 

 

2007-8-8
___________________________________________________________________________________________________________________________

工厂方法的用意:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的
实例化延迟到其子类

 

 

2007-8-8
___________________________________________________________________________________________________________________________

到底为什么要什么工厂模式?

——设计模式的学习这几天已经进入到了多种工厂模式了,说实话,这几种模式的结构都比较简单,学习起来并不怎么费力,但是我还是感到了工厂模式有其难学之处,这种难学之处不在于模式本身而在于对模式用意的体会与理解。说到底就是我们到底为什么要使用工厂模式?这个问题最近几天一直困扰着我,幸好近期看到了一本名为:《Professional.Refactoring to Patterns》的书,让我从重构的角度了对为什么要使用工厂模式有了一定的认识!

  一、构造器也有不好使的时候
 1.当构造逻辑过于复杂时,我们的构造器将会变得臃肿不堪,这就意味着它的责任应该分解!
  2.由于系统需要,我们不得不提供大量重载的构造器,但是由于构造器是一种特殊函数,这会使得它在某些方面可能不如普通函数灵活,比如:我们不能同时拥有两个参数列表相同的构造器(重载的限制),然而事实上这两个构造器可能实现完全不同的构造过程。而如果使用普通方法则可以用方法名加以区别!另外构造器在还一个天生的缺陷:即它不能实现多态地创建对象.一个子类的构造器不能重写父类的构造器,只能简单地调用.
  二、适时的使用静态工厂方法完成构造器所承担的责任(在简单情况下)
  三、当工厂方法过多过于复杂时,你要审问自己:是否当前的建造实例的逻辑已经大大地混淆了一个类原本应该承担的主要责任?如果答案是确定的,那么你就适时地把建造实例的逻辑抽离出来了,抽离到那里去呢?一个单独的专门用于创建实现的类,也就是工厂!

 

 

2007-8-10
___________________________________________________________________________________________________________________________

关于为什么要使用工厂模式以用如何使用工厂模式,我实在是不想多说了,因为我的任何话语同《Professional.Refactoring to Patterns》第六单《creation》所展示的重构过程相比都显得苍白无力。这一部分请一定要认真仔细地看看。我只想提出两点:
一:复杂的创建逻辑和创建时的配置过程都不应该是构造器的责任,它们应该放到一个或多个工厂方法中,至于是否要把这些方法单独的抽离出来,封装到一个工厂中,则要视情况而定。绝大多数情况下设计一个独立的工厂类总是好的,简单情况下可以将产品角色与工厂角色合并,让产品自己生产自己。见6.1
二:工厂并不应该总是提供几个工厂方法那么简单,对于复杂的创建逻辑和创建配置,它可能要做的有很多,像6.2中举出的例子:一个工厂负责生产客户定制的产品,定制产品本身就需要一些定制选项,毋庸置疑,这些定制选项应该都是工厂类的属性字段!

6.3把产品和类封装到一起!
  工厂方法模式的一种变形:合并工厂和产品,把用来生产“具体”产品的静态工厂方法移植到抽象产品中,这样做除了可以得到工厂模式的好处,还可以实现基于接口/抽象编程的目的。当然,这种方法也有不足之处:不能扩展,如果出现新的具体产品将不得不修改抽象产品。另外这种方法显然不适用于拥有过多子类的体系。
  关于这种模式的典型应该就是DateFormat抽象类,它有多个类似getDateInstance的方法,返回的实例都是SimpleDateFormat的实例!
  我觉得这种模式还是会经常遇到的,因为我们平常设计的类体系可能都不会太大太复杂,如果一个抽象类或是接口下面也就只一两个具体子类的话,单独再设计一个工厂体系可能太过兴师动众,使用这种模式既能发挥工厂模式的威力,又简化了设计,还保证的基于抽象进行编程。但是要记住,采用这种模式时,产品体系中必需要有一个抽象产品类。

 

 

2007-8-16
——————————————————————————————————————————————————
办什么需要工厂方法?看看下面两句话:

Classes in a hierarchy implement a method similarly, except for an object creation step.

Factory Methods are most common in object-oriented programs because they provide a way to make object creation polymorphic.

我们总是在努力地去试图基于抽象进行编程,我们总是想为我们的客户端提供一个抽象的接口.
在众多的模式里,我们通过多态和委托实现了很多巧妙的设计,但是,但是,我们在对象的创建问题上却是遇到了如此
尴尬的问题--构造方法不能重写!于是,我们创造了工厂方法,让对象的创造变成多态的,让对象的实例化工作从抽象类推迟到具体类!这为我们"全面"地推行基于抽象编程提供了保证!

 

 

2007-10-8
——————————————————————
状态模式和策略模式的异同:
这两个模式的解有很大的相似之处,以至于他们常常被混淆.它们的相同之处就在于:
两者都使用了委托,将抽象类声明的方法分派给不同的实现类去实现.这也导致了两者
的类图或者说结构几乎是一模一样的!
但是两者依然有着明显的不同之处!从用意上讲,状态模式注重于对象状态的变更,在执行一系列的操作过程中,对象的状态往往会发生多次的转换,而对于策略模式而言,一旦一个具体策略被选中,那这个策略将不会再变动.另外,策略的选择往往是由客户端来实现的,在而对于状态模式来说,对象的状态则是根据对象的执行的具体事务(操作)而由状态自己确定转向哪一个另外的状态,这不是由客户端来决定的,甚至对于客户端来说是透明的!

 

2007-10-10
—————————————————————————————————————————————
Null Object:空对象,一种非常有用的设计技巧,也可以是算是一种设计模式。

 

2007-12-9
_________________________________________________________________________________
Collecting Parameter:参数收集模式,一种小模式,当你需要多个方法的返回结果时,给这些方法添加一个Collecting Parameter,把该Collecting Parameter的一个实例的引用传给这些方法,让这些方法把计算结果写入该实例,从而实现收集的目的。

 

2008-2-17
_________________________________________________________________________________

In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. -----Martin Fowler.

2009-10-19

状态模式的核心用意是:
当一个对象的某些行为会因为其处于不同的状态而不同时,表现出的形式就是这些方法里有大量的if else,当是这种状态时,这样做,那种状态时
那样做。这种情况下,导致对象的这些方法痈肿且难于维护,尤其是当状态的种类有变化时,代码的修改量是非常大的。
状态模式的核心功用就是针对这些不同的状态进行建模,相应状态下的操作被抽离到状态类里!这样的话:变化的东西(那些
因状态不同而操作不同的方法)被单独抽离出来进行了封装。代码变得灵活而易于扩展。

转载于:https://my.oschina.net/pangzhuzhu/blog/327149

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值