w1100n
This site is best viewed in Google Chrome
wiloon, 8/8/2014 6:59 | Tag:

http://blog.sina.com.cn/s/blog_5f13e9910100g3ob.html http://www.iteye.com/topic/29541 委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托模式使得我们可以用聚合来替代继承,它还使我们可以模拟mixin。 “委托”在C#中是一个语言级特性,而在Java语言中没有直接的对应,但是我们可以通过动态代理来实现委托!代码如下: Java代码 收藏代码 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* * @author Liusheng * 实现“委托”模式,用户需要实现InvocationHandler接口; * 参考:http://www.uml.org.cn/j2ee/200411036.htm */ public abstract class Delegator implements InvocationHandler { //RelegateTo针对每个对象都要生成一个实例,因而非Static的log,代价比较高。 //protected Log _log = LogFactory.getLog(this.getClass()); //private static Log _log = LogFactory.getLog(RelegateTo.class); … Continue reading

wiloon, 10/16/2012 16:20 | Tag:

从JDK1.3开始,Java就引入了动态代理的概念。动态代理(Dynamic Proxy)可以帮助你减少代码行数,真正提高代码的可复用度。例如,你不必为所有的类的方法里面都写上相同的Log代码行,取而代之的是实用类的动态代理类。当然,这种便利是有条件的。本文简单介绍Java动态代理的原理,并实现一个被代理的Servlet创建,和调用的过程。 1.代理模式(Proxy Pattern) 在JDK1.3以前,代理模式就已流行,所以得代理模式是生成一个和类相同接口的代理类,用户通过使用代理类来封装某个实现类。如图1,其目的是加强实现类的某个方法的功能,而不必改变原有的源代码。 2.动态代理(Dynamic Proxy) 随着Proxy的流行,Sun把它纳入到JDK1.3实现了Java的动态代理。动态代理和普通的代理模式的区别,就是动态代理中的代理类是由java.lang.reflect.Proxy类在运行期时根据接口定义,采用Java反射功能动态生成的。和java.lang.reflect.InvocationHandler结合,可以加强现有类的方法实现。如图2,图中的自定义Handler实现InvocationHandler接口,自定义Handler实例化时,将实现类传入自定义Handler对象。自定义Handler需要实现invoke方法,该方法可以使用Java反射调用实现类的实现的方法,同时当然可以实现其他功能,例如在调用实现类方法前后加入Log。而Proxy类根据Handler和需要代理的接口动态生成一个接口实现类的对象。当用户调用这个动态生成的实现类时,实际上是调用了自定义Handler的invoke方法。 3.动态代理Servlet               虽然Web Application Server的产品很多,但Servlet的处理原理是相似的:动态加载Servlet,调用Servlet的init方法(只被调用一次),并保存到Servlet容器;Servlet使用时,调用Servlet的service方法。本文动态代理Servlet接口,使其init和service被调用时会在控制台打出方法调用前后信息。 首先实现2个Servlet,DefaultServlet和UserServlet 其中的ServletConfig保存Servlet相关信息。ServletContext保存所有的Servlet对象。WebAppClassLoader为自定义class loader,参见http://blog.csdn.net/tyrone1979/archive/2006/09/03/1164262.aspx。 最后编写测试类Main,该类模拟10个用户访问Servlet,5人访问DefaultServlet,5人访问UserServlet。 HttpServletRequestWrapper和HttpServletResponseWrapper实现HttpServletRequest,和HttpServletResponse。 测试结果如下 org.colimas.servlet.DefaultServlet:Init servlet starting… org.colimas.servlet.DefaultServlet:Running init org.colimas.servlet.DefaultServlet:Init servlet ending… org.colimas.servlet.UserServlet:Init servlet starting… org.colimas.servlet.UserServlet:Running init org.colimas.servlet.UserServlet:Init servlet ending… org.colimas.servlet.DefaultServlet:service starting… org.colimas.servlet.DefaultServlet:service ending… org.colimas.servlet.DefaultServlet:service starting… … Continue reading

wiloon, 10/16/2012 14:09 | Tag:

静态内部类 static nested class 这种方法也是《Effective Java》上所推荐的。 这种写法仍然使用JVM本身机制保证了线程安全问题;由于 SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,因此它是懒汉式的;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖 JDK 版本。 单例模式(Singleton) 1.介绍:也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。 2.实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称); 当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。 3.注意事项:单例模式在多线程的应用场合下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式中实例唯一的原则。 解决这个问题的办法是为指示类是否已经实例化的变量提供一个互斥锁(虽然这样会降低效率)。 4.实现方式:通常单例模式在Java语言中,有两种构建方式: 饿汉方式:指全局的单例实例在类装载时构建。(一般认为这种方式要更加安全些) 懒汉方式:指全局的单例实例在第一次被使用时构建。 5.示例: http://blog.csdn.net/qjyong/article/details/1721342 http://wuchong.me/blog/2014/08/28/how-to-correctly-write-singleton-pattern/ http://www.iteye.com/topic/537563 https://github.com/pzxwhc/MineKnowContainer/issues/74 http://www.wiloon.com/wordpress/?p=9951

wiloon, 10/12/2012 16:26 | Tag:

http://www.cnblogs.com/shenfx318/archive/2007/01/28/632724.html 在设计模式的学习过程中,Builder与Factory是创建模式中两个经典的教程,给与了我们很多值得汲取的宝贵设计思想,然而Builder与Factory模式也是初学者容易混淆的两个模式,经常看到有人问及两者的区别与适用的场景,我在近一段设计模式的学习过程中同样碰到了这个问题,在两种模式的区别与联系间我看到的更多是后者,在这里愿意与大家分享一些我对Builder与Factory模式的感悟,有说的不对的地方,还请各位多加提点、指教。 写在前面 本文旨在两种模式间的对比与探讨,因此还希望各位看官首先对两个模式有一定的了解为好,因为常常看到有人提问说,Builder模式与抽象工厂(Abstract Factory)之间的区别,其实在我看来这两者间并无太多联系,因此也就谈不上区别,至于原因在此不做细述,有兴趣的朋友可以看看我写的有关抽象工厂的文章。故本文中所提的Factory模式皆指的是工厂方法(Factory Method)。 从Builder到Factory的演化 先来看看Builder模式,Builder模式的一般设计及实现 客户端调用代码 从类关系图上来看,Builder模式与我们熟知的工厂模式还是具有一定的区别,最显著的莫过于这个指导者(Director)的角色,我们观察这个Director,发现他无非是以参数的形势接收了一个Builder,并按照一定的顺序调用其相应的方法构造各个部件,使得Builder可以完成最终的产品。这其实是对复杂对象构造顺序的封装,但我们可以看到仅仅为了做这一件事情是否有必要为它单独设计一个类?每次都要实例化这个类的对象呢?既然建造顺序是相对稳定的,而且对于客户来讲并不关心这个顺序,那么是否可以将它与Builder类结合?当然可以,实际中也确实常常进行这样的简化,比如StringBuilder类,我们看不到类似Director对象的存在及调用。好,那么经过我们一次的改造以后,变成了如下形式。 客户端调用代码 再看看客户端中的这条Builder.Construct()语句,似乎也有些多余了,客户一般只有在需要产品的时候才会实例化一个Builder对象,因此对于客户来讲,他创建了Builder意味着他需要Builder能够为他生成一个产品(GetProduct),而返回产品必然需要构造Construct,于是我们又可以对代码进一步简化,将Construct方法与GetProduct方法结合。 对了,客户是不关心这个复杂对象的建造生成过程的,也就是说BuildPartN(),这些方法对于客户是没有意义的,是不可见的,那么我们就将其声明为private,而GetProduct只是方法的一个名称,叫什么都可以,你可以叫GetResult,ReturnProduct….把它称为Create亦可。OK,之后再来看看改造后的类图。 OMG! 从图上来看,除了名称叫做Builder外,其他根本和Factory模式没有什么区别,从代码来看,不过是工厂模式在返回具体的产品前对该产品进行了一些初始化的工作。 就是这些代码,我们将其挪个地方改个名称又何尝不可呢? 好了,通过对Builder模式向Factory的一步步演化,我们可以看到两者实质上并没有太多的区别,这也就是本文想要阐述的观点,也许很多朋友这时会反驳我了,说两者怎么会没有区别呢? Builder模式用于创建复杂的对象。 对象内部构建间的建造顺序通常是稳定的。 对象内部的构建通常面临着复杂的变化。 对于持以上观点的朋友,我也有如下一些疑问。 什么样的对象属于复杂的对象?关于对象复杂与否是如何划分的? 站在客户的角度来讲,是否关心对象的复杂程度及建造顺序? 既然客户不关心对象是否复杂以及生成的顺序,那么将这个复杂对象分布构建的意义就在于它有益于设计方了,对于设计人员,复杂对象分布构建的分布体现在哪里?是依次写几行代码还是依次调用几个方法? 这种分布给你带来了哪些好处?可以帮助你应付哪些变化? 既然我们不是为了学习设计模式而学习,而是为了学习OOD的精髓,能够编写出更加灵活,适用于需求变化的软件。那么对于需求变化,我们不妨再来看看两个模式是如何应对的。Builder模式适用场景中的第3条提到了”变化”二字:对象内部的构建通常面临着复杂的变化。就拿PartA为例,现在这个对象发生了剧烈的变化,对于Builder来讲,修改BuildPartA()方法显然是违反OCP的,于是采取第二种方法,从抽象Builder派生一个新的NewBuilder类,为这个新的Builder添加变化后的BuildPartA()方法,其余BuildPart方法不变。代码如下。 你可能会认为,我改造后的Factory就不叫Factory了,已经失去了Factory的本意,好吧,那我们暂且抛开它的名称,换个角度来看看Builder与Factory,Builder具有Factory应付不了的情况吗?没有!因为对象很复杂,所以使用Builder构建对象功能更强大,更具有灵活性吗?没有!客户对于取得产品的过程,以及最终产品的使用有区别吗?没有!因此Builder仅仅是在代码的结构上与Factory产生了一些异同,使得用户可以在取得产品前对产品进行一定的初始化工作。如果这也能够称为新模式的话,那么只能说个人对于设计间区别的理解不同。 还有最后要说的一点,关于建造者模式中第2条:对象内部构建间的建造顺序通常是稳定的,这点在我看来也难以构成对于与Factory模式区别的理由,因为Factory模式从来就没有考虑对象的建造顺序!只有不稳定的东西才能带来变化的可能性,将稳定的不会变化的东西也作为设计模式的理由是否有些牵强了? 本文仅代表了作者当时的认知程度与观点,文中之所以主要强调了两个模式间的相同点还是因为本人的水平有限未能找到合适的例子来区分二者,还希望大家各抒己见,为在下答疑解惑。

wiloon, 10/12/2012 16:26 | Tag:

http://www.cnblogs.com/shenfx318/archive/2007/01/16/621237.html 在我的上一篇文章(疑惑?改良?从简单工厂到工厂方法)中,详细论述了创建模式中简单工厂到工厂方法的演变过程,并试图结合工厂方法的设计以及.net中的反射机制之所长,改良出一种新型的工厂—反射工厂,这当然不是我的首创,经典的PetShop 中便有此工厂的身影。本文尝试按照前篇文章的思路,借着工厂方法到抽象工厂的演变过程而继续对抽象工厂进行改良,文章中的思想仅代表了作者当时的观点,有欠妥的地方,还请各位不吝赐教。 工厂模式 前面的文章提到了简单工厂和工厂方法其实是一码事,他们完成了将客户对产品功能的使用与创建具体产品职责的分割,不同的只不过是他们实现方式上的差异,工厂方法利用更加优雅的多态性取代了相对ugly的switch case…语句,从而很好的体现了设计原则中的OCP原则,此文章将不再强调这种实现上的差异性,而更多的强调两者之间设计思路上的共性,并将这种共性统称成为工厂模式,从而进一步与抽象工厂进行对比。 工厂的使用,选择的过程 工厂模式的使用,实际上是客户(产品的消费者)对于产品选择的过程,对于实现了相同功能的产品来讲,客户更加关心的是产品间的差异性,而工厂的作用则是将产品的生产过程封装,根据客户的要求直接返回客户需要的产品。注意,工厂只是隐藏了产品的生产过程,但是并没有剥夺客户选择的权利,那么客户的这个选择过程又是如何体现的呢?在简单工厂中,客户通过参数的形式告诉工厂需要什么样的产品,而在工厂方法中,客户通过对工厂的选择代替了直接对产品的选择,注意到工厂方法中一个工厂只有一个Create方法,也就是说一个工厂只负责生产一种产品,那么你选择了相应的工厂也就等同于你选择了对应的产品。就连改良后的反射工厂也没有消去对产品的选择,只不过是将这种选择外化(外化到配置文件中,从而使得对代码的改动最小)。可以说,正是由于产品间的差异性带给了客户选择的权利,这种权利是不应当被工厂取代的,那么工厂模式的价值又在哪里呢?答案是抽象与封装,工厂模式将由于客户的不同选择而可能导致的对已知事物的影响降到最低,途径是通过抽象产品取代具体产品,使得客户依赖于抽象(越抽象的东西越稳定),同时将客户的选择封装到一处,隔离与具体产品间的依赖。 工厂模式与抽象工厂 前面说了这么多无关的,为得是做好铺垫,更加有益于对下文的理解,OK,终于该说说从工厂模式到抽象工厂的转变了,先来对比两张类图: 工厂方法(Factory Method) 抽象工厂(Abstract Factory) 从图中我们能够看到哪些差异? 最明显的一点就是在工厂方法的类关系图中只有一类产品,他们实现了一个统一的接口,而抽象工厂有多个类别的产品,他们分别实现了不同的功能(多个接口)。其次的一点差别就是工厂本身所具有的方法数量不同,这点差异其实也是由第一点所导致的,工厂需要有生产不同类别产品的功能,如果抽象工厂中的产品的功能简化到一个,也便成为了工厂方法。 引出类别的概念,类别是指具有相同功能的一类产品的总称。 再来看选择的过程,在工厂方法中,客户关心的只不过是实现同一样功能的不同产品间的差异,这是一个一维选择的过程。 1             IFactory factory = new FactoryA(); //选择了工厂即选择了产品 2             IProduct productA = factory.Create(); //工厂只有一个Create方法,只能生产一种产品 而在抽象工厂中,客户首先要考虑的是需要哪一样功能,其次要考虑才是产品间的差异。也就是说这是一个二维选择的过程。 1             IFactory factory = new FactoryA(); //选择了某个具体工厂 2             IProduct productA = factory.CreateProductA(); //工厂具有多个Create方法,这里选择了其中的一个 由于产品类别的增加而导致客户在考虑产品间差异的同时还要考虑产品间功能的差异,这种二维选择的过程才是工厂方法与抽象工厂之间的本质区别。 举个肯德基与麦当劳的例子,假设原来只有一家快餐店叫做麦当劳,提供的食物(具体产品)有汉堡、可乐、薯条,它们都可以满足你吃东西(抽象接口)的需求,那么你想吃快餐的时候,唯一的选择就在于吃什么,是一维选择,现在又开了一家快餐店叫做肯德基,同样供应汉堡、可乐和薯条,那么现在你若打算吃快餐,除了考虑吃什么外,还要考虑去哪里吃–肯德基还是麦当劳?这便是二维的选择。通过横向与纵向的选择才能最终锁定你要的产品。   引入系列的概念,相互间具有差异的同一类别的产品称为不同的系列,如肯德基和麦当劳就是两个不同的系列。 这种选择的区别带来的另外一个后果就是产品间的差异(系列间的差异)变为客户的次要选择,而客户主要的精力放在了功能的选择上(类别的选择)。 我们结合实例来看看抽象工厂的一般设计及实现 客户调用代码 1             AbstractFactory factory = new McDFactory(); //选择去麦当劳吃 2             IHamburger hamburger = factory.CreateHamburger(); //选择吃汉堡 可以看到系列间的选择由工厂的选择来替代,而类别间的选择实际上就是工厂内不同类别产品创建方法的选择。那么如此这般设计是否有依据呢?我们为什么不将工厂设计成为汉堡工厂,可乐工厂和薯条工厂呢?这其实是刚接触抽象工厂的人经常陷入的误区,这个问题的关键在于需求!需求是来自于客户的,工厂的设计取决于客户怎样使用产品。在这个例子中,之所以要将汉堡、可乐和薯条设计为类别而不是系列,首先是因为他们对于客户有不同的功能,例如汉堡可以充饥,薯条可以解馋、可乐可以解渴,任何一个客户希望走进一家店(无论是肯德基还是麦当劳)都能够得到上面的这三种功能,这才是客户真正的需求!如果客户选择走进了麦当劳,那么他就永远不会吃到肯德基的食品。这里有点绕可能需要多想一下,再举个例子帮助理解,比如星际争霸游戏,里面有三个种族,每个种族的兵营都能生产三种兵,如何选定类别与系列?抛开游戏的设计来讲,从用户的角度出发,我们还是会把系列对应成种族,那是因为任何一个玩家进入游戏后,都希望能够体验三个不同的兵种所具有的不同能力,而不是希望拥有一个能够制造出所有三个种族一级兵的兵营。反过来讲,用户每次进入游戏只可能选择一个种族,如果他这次选择了虫族,那么他就永远不可能生产出机枪兵。 最后再将上面提到的种种概念进行一下总结 类别 = 接口 = 抽象产品 = … Continue reading

wiloon, 10/11/2012 14:53 | Tag:

选这4个模式在一起讨论首先是因为它们的功能比较类似,都是用来制造对象实例的,从归类来说,他们都属于制造类模式(creational patterns),其次她们们在工作中比较常用,由于功能太过相似,往往导致在某个实际问题上让人举棋不定,似乎选哪个都可以解决问题,可是真的选择某个模式后,又会发现不是完全合适。今天我们就来讨论讨论在什么情况下选择什么模式来解决问题比较合适。 考虑到不是所有的朋友都对以上提到的4种模式都了如指掌,在开始讨论之前先简单的介绍一下这4个模式,对这4种模式熟悉的朋友也可以顺便回顾一下。请注意,这里我只会做简短的介绍,如果要比较深入地了解她们的话,还请去看模式相关的书籍,比较浅显易懂的我推荐 “Head First Design Patterns”。如果要在工作中反复参考的我推荐 “Applied Java Patterns”。那本经典的GOF Design Patterns由于写的时间比较早,举的例子不太适合现在的软件开发,我个人认为初学者或者是没有太多时间的朋友没有必要去读那本书,尽管她的确是经典。 Factory Pattern 中文叫工厂模式, 这个是我们在面向对象编程中最常用的模式之一了,她的主要功能就是制造对象,也正是这个原因才叫她为工厂模式,工厂干什么?生产产品。通常情况而言某个工厂所生产的产品总是一个系列的不同种类,大体上相同,细节上有差异。 图1 展示了一个非常简单的例子,通常CarFactory类会提供下列方法来生产车辆, 如代码片断1所示: public class CarFactory { public Car createBusinessCar() {….} public Car createSportCar() {…} } 代码片断 1 图1 Factory Pattern Abstract Factory Pattern … Continue reading

wiloon, 10/10/2012 12:23 | Tag:

对于Builder模式很简单,但是一直想不明白为什么要这么设计,为什么要向builder要Product而不是向知道建造过程的Director要。刚才google到一篇文章,总算清楚了。在这里转贴一下这位richardluo的比喻。 简单地说,就好象我要一座房子住,可是我不知道怎么盖(简单的砌墙,层次较低),也不知道怎么样设计(建几个房间,几个门好看,层次较高),于是我需要找一帮民工,他们会砌墙,还得找个设计师,他知道怎么设计,我还要确保民工听设计师的领导,而设计师本身也不干活,光是下命令,这里砌一堵墙,这里砌一扇门,这样民工开始建设,最后,我可以向民工要房子了。在这个过程中,设计师是什么也没有,除了他在脑子里的设计和命令,所以要房子也是跟民工要,记住了! 以下是richardluo的代码,我根据他的思路加上了相应的注释。 1,定义工人接口,就是能够完成建造房子任务的人的通用要求。 3,民工,他负责具体事物的实施。 4,房主,就是雇人,收房。 好了,我觉得这样大概能说明白了。不知各位觉得如何呢?或者有更好的应用场景解释,敬请赐教。  [GOF95]中,Builder模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 Builder模式和AbstractFactory模式在功能上很相似,因为都是用来创建大的复杂的对象,它们的区别是:Builder模式强调的是一步步创建对象,并通过相同的创建过程可以获得不同的结果对象,一般来说Builder模式中对象不是直接返回的。而在AbstractFactory模式中对象是直接返回的,AbstractFactory模式强调的是为创建多个相互依赖的对象提供一个同一的接口。 http://blog.csdn.net/surprisesdu/article/details/621046 http://smartfool.iteye.com/blog/71175

wiloon, 10/10/2012 11:25 | Tag:

Prototype模式是一种对象创建型模式,它跟工厂模式,Builder模式等一样,都用来创建类的实例对象。 但Prototype模式的对象创建方法,具有以下特点: – 由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。 – 目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。 – 根据对象克隆深度层次的不同,有浅度克隆与深度克隆。 简单一点说, Prototype模式提供一种方法,让类的对象可以实现对自身的复制。 Prototype模式的应用场景: – 在创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据。 – 希望对目标对象的修改不影响既有的原型对象(深度克隆的时候可以完全互不影响)。 – 隐藏克隆操作的细节。很多时候,对对象本身的克隆需要涉及到类本身的数据细节。 现实生活中,就有许多这样的例子: 生物细胞的自身复制;根据产品模型生产产品等等 Prototype模式的模型定义: Prototype { +clone():Prototype } 即:原型类Prototype 提供clone()方法,实现对对象自身的复制(克隆)。 Prototype模式的实现范例 下面我们使用Prototype模式来实现细胞(Cell)的自身复制过程。 Java语言提供了对象复制的机制,Prototype模式的Java实现一般也通过实现Cloneable接口来实现。 这里我们也通过实现Cloneable接口来说明Prototype模式。 public   class  Cell  implements  Cloneable {     //细胞壁     private  String cellWall;     //细胞膜     private  String cellMembrane;     //细胞组织     private  String cellularTissue;     …//这里省略掉了对成员变量的setter/getter方法的定义     //细胞的自身复制     //这里重载了Obect#clone()方法,为了方便外部调用,把返回值由Object修改为Cell,并把访问级别设置为public … Continue reading

wiloon, 10/9/2012 16:57 | Tag:

抽象工厂模式中的有以下的四种角色: 抽象工厂(Abstract Factory)角色:担任这个角色的是工厂方法模式的核心,它是与应用系统业务逻辑无关的。 具体工厂(Concrete Factory)角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的业务逻辑紧密相关的。 抽象产品(Abstract Product)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。 具体产品(Concrete Product)角色:这个角色用以代表具体的产品。 抽象工厂模式就相当于创建实例对象的new,由于经常要根据类生成实例对象,抽象工厂模式也是用来创建实例对象的,所以在需要新的事例对象时便可以考虑是否使用工厂模式。虽然这样做可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。 举例来说:生产餐具和相应食物的工厂,有两个车间,其中一个车间用以生产餐具,一个车间用以生产相应的食物。 当消费者消费时,只需要向相应的具体工厂请求具体餐具和具体食物便可以使用餐具消费食物。 每个具体工厂生产出来的具体产品根据不同工厂的不同各不相同,但是客户使用产品的方法是一致的。比如客户在得到餐具和食物之后,两者的搭配是正确的(使用汤匙喝牛奶,使用刀子切面包)。 在本例子中有3个具体工厂AKetchen, BKetchen, BKetchen,分别生产牛奶和汤匙、面包和刀、肉和叉子。牛奶、面包和肉都实现了食物接口。汤匙、刀和叉子都实现了餐具接口。 抽象工厂的接口定义如下所示; 小结:抽象工厂模式特别适合于这样的一种产品结构:产品分为几个系列,在每个系列中,产品的布局都是要同的,在一个系列中某个位置的产品,在另一个系列中一定有一个对应的产品。这样的产品结构是存在的,这几个系列中同一位置的产品可能是互斥的,它们是针对不同客户的解决方案,每个客户都只择其一。 优点:消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。 缺点:当具体产品修改时,相应的工厂类也要做相应的修改。 如果觉得写得好,请一定要支持一下,以给我信心和鼓励把剩下的模式例子写出来。 本文出自 “凌辉” 博客,请务必保留此出处http://tianli.blog.51cto.com/190322/32545

wiloon, 10/8/2012 16:25 | Tag:

开闭原则(Open-Close Principle/OCP)是面向对象设计中“可复用设计”的基石,是面向对象设计中最重要的原则之一,其它很多的设计原则都是实现开闭原则的一种手段。 1988年,Bertrand Meyer在他的著作《Object Oriented Software Construction》中提出了开闭原则,它的原文是这样:“Software entities should be open for extension,but closed for modification”。翻译过来就是:“软件实体应当对扩展开放,对修改关闭”。这句话说得略微有点专业,我们把它讲得更通俗一点,也就是:软件系统中包含的各种组件,例如模块(Modules)、类(Classes)以及功能(Functions)等等,应该在不修改现有代码的基础上,引入新功能。开闭原则中“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;开闭原则中“闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代码。实现开闭原则的关键就在于“抽象”。把系统的所有可能的行为抽象成一个抽象底层,这个抽象底层规定出所有的具体实现必须提供的方法的特征。作为系统设计的抽象层,要预见所有可能的扩展,从而使得在任何扩展情况下,系统的抽象底层不需修改;同时,由于可以从抽象底层导出一个或多个新的具体实现,可以改变系统的行为,因此系统设计对扩展是开放的。 我们在软件开发的过程中,一直都是提倡需求导向的。这就要求我们在设计的时候,要非常清楚地了解用户需求,判断需求中包含的可能的变化,从而明确在什么情况下使用开闭原则。 关于系统可变的部分,还有一个更具体的对可变性封装原则(Principle of Encapsulation of Variation, EVP),它从软件工程实现的角度对开闭原则进行了进一步的解释。EVP要求在做系统设计的时候,对系统所有可能发生变化的部分进行评估和分类,每一个可变的因素都单独进行封装。 我们在实际开发过程的设计开始阶段,就要罗列出来系统所有可能的行为,并把这些行为加入到抽象底层,根本就是不可能的,这么去做也是不经济的,费时费力。另外,在设计开始阶段,对所有的可变因素进行预计和封装也不太现实,也是很难做得到。所以,开闭原则描绘的愿景只是一种理想情况或是极端状态,现实世界中是很难被完全实现的。我们只能在某些组件,在某种程度上符合开闭原则的要求。 通过以上的分析,对于开闭原则,我们可以得出这样的结论:虽然我们不可能做到百分之百的封闭,但是在系统设计的时候,我们还是要尽量做到这一点。 对于软件系统的功能扩展,我们可以通过继承、重载或者委托等手段实现。以接口为例,它对修改就是是封闭的,而对具体的实现是开放的,我们可以根据实际的需要提供不同的实现,所以接口是符合开闭原则的。如果一个软件系统符合开闭原则的,那么从软件工程的角度来看,它至少具有这样的好处: 可复用性好。 我们可以在软件完成以后,仍然可以对软件进行扩展,加入新的功能,非常灵活。因此,这个软件系统就可以通过不断地增加新的组件,来满足不断变化的需求。 可维护性好。 由于对于已有的软件系统的组件,特别是它的抽象底层不去修改,因此,我们不用担心软件系统中原有组件的稳定性,这就使变化中的软件系统有一定的稳定性和延续性。开闭原则具有理想主义的色彩,它是面向对象设计的终极目标。因此,针对开闭原则的实现方法,一直都有面向对象设计的大师费尽心机,研究开闭原则的实现方式。后面要提到的里氏代换原则(LSP)、依赖倒转原则(DIP)、接口隔离原则(ISP)以及抽象类(Abstract Class)、接口(Interface)等等,都可以看作是开闭原则的实现方法。 http://baike.baidu.com/view/866233.htm

wiloon, 11/20/2011 12:42 | Tag:

观察者模式(有时又被称为发布-订阅模式、模型-视图模式、源-收听者模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。 观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。 观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。在刚才的例子中,业务数据是被观察对象,用户界面是观察者。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。如果在用户界面、业务数据之间使用这样的观察过程,可以确保界面和数据之间划清界限,假定应用程序的需求发生变化,需要修改界面的表现,只需要重新构建一个用户界面,业务数据不需要发生变化。 实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。 实现观察者模式有很多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式。 1、观察者 (Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。 2、被观察对象 被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。 3、撤销观察 观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。 观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,让他们能够自动更新自己 观察者模式的组成 1.抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类或接口来实现 2.抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。 3.具体主题角色(Watched):把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类或接口来实现。 4.具体观察者角色(Watcher):为所有具体的观察者定义一个接口,在得到主题的通知时更新自己 A.自定义观察者模式 例如: 1.抽象主题角色类 2.抽象观察者角色 3.具体主题角色(Watched) 4.具体观察者角色(Watcher) 5.客户端调用: 执行结果为: 第1次… update….. update….. update….. 第2次… update….. update….. 第3次… B:对于java的观察者模式框架 从AWT1.1开始图形系统的事件模型采用观察者模式,因此观察者模式在Java语言中的地位极其重要 在xml解析中的SAX也采用了观察者模式来实现 Java也提供了对观察者模式的内置支持 内置观察者模式主要有2个类,一个是类Observable,一个是接口类Observer Observable类是被观察者,子类只要继承它即可。而且添加观察者等方法已经都实现了. … Continue reading

wiloon, 10/29/2011 11:06 | Tag:

芹菜叶 芹菜叶焯水 攥干 切段 加入蒜末 加醋 生抽 盐 鸡精 糖 香油 茄子炒黄瓜 茄子、黄瓜切丁,蒜切好 放入蒜炒香,然后先炒茄子,油要大,把茄子炒软 放入黄瓜丁,加入两大铲子老抽、一勺糖、一点盐,充分混合,保留茄子的软糯和黄瓜的爽脆,出锅!

wiloon, 10/29/2011 7:59 | Tag:,

GoF的23种设计模式: 创建模式 Simple Factory Pattern 简单工厂模式 http://www.wiloon.com/wordpress/?p=1339 Factory Method Pattern 工厂方法模式 Abstract Factory Pattern 抽象工厂模式   prototype   Builder   Singleton 结构模式   Facade   Proxy   Adapter   Composite   Decorator,装饰器http://www.wiloon.com/wordpress/?p=847   Bridge   Flyweight 行为模式   Template Method, 模板方法 http://www.wiloon.com/wordpress/?p=5526   Memento   Observer — 观察者 http://www.wiloon.com/wordpress/?p=1558   Chain Of Responsibility   Command … Continue reading

wiloon, 10/29/2011 6:32 | Tag:

一、引子 话说十年前,有一个暴发户,他家有三辆汽车——Benz奔驰、Bmw宝马、Audi奥迪,还雇了司机为他开车。不过,暴发户坐车时总是怪怪的:上Benz车后跟司机说“开奔驰车!”,坐上Bmw后他说“开宝马车!”,坐上Audi说“开奥迪车!”。你一定说:这人有病!直接说开车不就行了?! 而当把这个暴发户的行为放到我们程序设计中来时,会发现这是一个普遍存在的现象。幸运的是,这种有病的现象在OO(面向对象)语言中可以避免了。下面就以Java语言为基础来引入我们本文的主题:工厂模式。 二、分类 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。 工厂模式在《Java与模式》中分为三类: 1)简单工厂模式(Simple Factory) 2)工厂方法模式(Factory Method) 3)抽象工厂模式(Abstract Factory) 这三种模式从上到下逐步抽象,并且更具一般性。 GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。 两者皆可,在本文使用《Java与模式》的分类方法。下面来看看这些工厂模式是怎么来“治病”的。 三、简单工厂模式 简单工厂模式又称静态工厂方法模式。从命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。 先来看看它的组成: 1) 工厂类角色:这是本模式的核心,含有一定的业务逻辑和判断逻辑。在java中它往往由一个具体类实现。 2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。 3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。 来用类图来清晰的表示下的它们之间的关系(如果对类图不太了解,请参考我关于类图的文章):   那么简单工厂模式怎么来使用呢?我们就以简单工厂模式来改造暴发户坐车的方式——现在暴发户只需要坐在车里对司机说句:“开车”就可以了。 将本程序空缺的其他信息填充完整后即可运行。如果你将所有的类放在一个文件中,请不要忘记只能有一个类被声明为public。本程序在jdk1.4 下运行通过。 程序中各个类的关系表达如下:   这便是简单工厂模式了。怎么样,使用起来很简单吧?那么它带来了什么好处呢? 首先,使用了简单工厂模式后,我们的程序不在“有病”,更加符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责“消费”产品(正如暴发户所为)。 下面我们从开闭原则(对扩展开放;对修改封闭)上来分析下简单工厂模式。当暴发户增加了一辆车的时候,只要符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。所以对产品部分来说,它是符合开闭原则的;但是工厂部分好像不太理想,因为每增加一辆车,都要在工厂类中增加相应的业务逻辑或者判断逻辑,这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类(在我们的例子中是司机师傅),我们称它为全能类或者上帝类(God Class)。 我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员:( 于是工厂方法模式作为救世主出现了。 … Continue reading

wiloon, 10/29/2011 6:02 | Tag:

工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。 为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。 我们以类Sample为例, 如果我们要创建Sample的实例对象: 可是,实际情况是,通常我们都要在创建sample实例时做点初始化的工作,比如赋值 查询数据库等。 首先,我们想到的是,可以使用Sample的构造函数,这样生成实例就写成: 但是,如果创建sample实例时所做的初始化工作不是象赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那你的代码很难看了(就需要Refactor重构)。 为什么说代码很难看,初学者可能没有这种感觉,我们分析如下,初始化工作如果是很长一段代码,说明要做的工作很多,将很多工作装入一个方法中,相当于将很多鸡蛋放在一个篮子里,是很危险的,这也是有背于Java面向对象的原则,面向对象的封装(Encapsulation)和分派(Delegation)告诉我们,尽量将长的代码分派“切割”成每段,将每段再“封装”起来(减少段和段之间偶合联系性),这样,就会将风险分散,以后如果需要修改,只要更改每段,不会再发生牵一动百的事情。 在本例中,首先,我们需要将创建实例的工作与使用实例的工作分开, 也就是说,让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去。 这时我们就需要Factory工厂模式来生成对象了,不能再用上面简单new Sample(参数)。还有,如果Sample有个继承如MySample, 按照面向接口编程,我们需要将Sample抽象成一个接口.现在Sample是接口,有两个子类MySample 和HisSample .我们要实例化他们时,如下: 随着项目的深入,Sample可能还会”生出很多儿子出来”, 那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的. 但如果你一开始就有意识使用了工厂模式,这些麻烦就没有了. 工厂方法 你会建立一个专门生产Sample实例的工厂: 那么在你的程序中,如果要实例化Sample时.就使用 Sample sampleA=Factory.creator(1); 这样,在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会,这个原理可以用很通俗的话来比喻:就是具体事情做得越多,越容易范错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,犯错误可能性就越少.好象我们从编程序中也能悟出人生道理?呵呵. 使用工厂方法 要注意几个角色,首先你要定义产品接口,如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factory类,用来生成产品Sample。 抽象工厂 工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory). 这两个模式区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,如上面工厂方法中是创建一个对象Sample,如果我们还有新的产品接口Sample2. 这里假设:Sample有两个concrete类SampleA和SamleB,而Sample2也有两个concrete类Sample2A和Sample2B 那么,我们就将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现,下面就是将上例中的Factory拓展成抽象工厂: … Continue reading

wiloon, 9/22/2011 7:48 | Tag:

Decorator设计模式是典型的结构型模式 装饰模式:Decorator常被翻译成”装饰”,我觉得翻译成”油漆工”更形象点,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称decoratee.这两种实体在Decorator模式中是必须的. Decorator定义: 动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活. 下面是GOF的《Element of reusable Object-Oriented Software》中对Decorator用意的概述: Decorator Pattern――Attaches additional responsibilities to an object dynamically . Decorators provide a flexible alternative to subclassing for extending functionality . 1 何时需要使用装饰器模式 GOF的那本Bible中关于装饰器模式列举的是一个文本组件与边框的例子 下面举一个“三明治”的例子! 很多人都吃过三明治,都会知道三明治必不可少的是两块面包片,然后可以在夹层里加上蔬菜、沙拉、咸肉等等,外面可以涂上奶油之类的。假如现在你要为一个三明治小店构造一个程序,其中要设计各种三明治的对象。可能你已经创建了一个简单的Sandwich对象,现在要产生带蔬菜的就是继承原有的Sandwich添加一个蔬菜的成员变量,看起来很“正点”的做法,以后我还要带咸肉的、带奶油的、带蔬菜的又分为带青菜的、带芹菜的、生菜的……还是一个一个继承是吧!假如我们还需要即带蔬菜又带其它肉类,设置我们还要求这些添加成分的任意组合,那你就慢慢继承吧! 读过几年书的会下面这个算术,我们有n种成分,在做三明治的时候任意搭配,那么有多少种方案呢?!算算吧!你会有惊人的发现。N种成分,什么都不要是Cn0种方案吧!要1种是Cn1吧!…..要n种是Cnn吧!加起来不就是吗?Cn0+Cn1+……+Cnn-1+Cnn还不会啊!牛顿莱布尼兹公式记得吧!(可惜Word的公式编辑器安装不了)总共2的n次方案。有可能前面10天写了K个类,老板让你再加一种成分你就得再干10天,下一次再加一种你可得干20天哦!同时你可以发现你的类库急剧地膨胀!(老板可能会说你:XXX前K天你加了n个成分,怎么现在这么不上进呢?后K天只加了1个成分啊?!!可能你会拿个比给老板算算,老板那么忙会睬你吗?!有可能你的老板会说:不管怎么样我就要你加,K天你还给我加n个成分!!呵呵,怎么办啊!跳槽啊!跳槽了也没人要你!!人家一看就知道你没学设计模式)。下面我们就使用装饰器模式来设计这个库吧! 下面是各个类的意义: 1. Ingredient(成分):所有类的父类,包括它们共有的方法,一般为抽象类且方法都有默认的实现,也可以为接口。它有Bread和Decorator两个子类。这种实际不存在的,系统需要的抽象类仅仅表示一个概念,图中用红色表示。 2. Bread(面包):就是我们三明治中必须的两片面包。它是系统中最基本的元素,也是被装饰的元素,和IO中的媒质流(原始流)一个意义。在装饰器模式中属于一类角色,所以其颜色为紫色。 … Continue reading

辽ICP备14012896