GOF设计模式

创建型模式
-单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
结构型模式:
-适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
行为型模式:
-模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

单例模式
核心作用:
—保证一个类中只有一个实例,并且提供一个访问该实例的全局访问点。

常见应用场景:
-Windows的Task Manager(任务管理器)就是很典型的单例模式
-Windows的Recycle Bin也是很典型的单例引用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
-项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,每次new一个对象去读取。
-网站的计数器,一般也是采用单例模式实现,否则难以同步。
-应用程序的日志应用
-数据库连接池的设计也是采用单例模式,因为数据库是一种数据库资源。
-操作系统的文件系统,也是大的单例模式具体实现的例子,一个操作系统只能有一个文件系统。

单例模式的优点:
—由于单例模式只生成一个实例减少了系统性能开销,当一个对象产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用程序启动时直接产生单例对象,然后永久驻留内存的方式来解决。
—单例模式可以在系统设置全局的访问点,优化共享资源的访问,例如可以设计一个单例类,负责所有数据表的映射处理。


常见的五种单例设计模式
-主要:
*饿汉式(线程安全,调用效率高,但是不能延时加载)
*懒汉式(线程安全,调用效率不高,但是可以延时加载)
-其他:
*双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题。)
*静态内部类式(线程安全,调用效率高,但是,可以延时加载)
*枚举单例(线程安全,调用效率高,不能延时加载)

饿汉式实现
public class SingletonDemo01{
        private static SingletonDemo01 s=new SingletonDemo01();
        private SingletonDemo01(){}
        public static SingletonDemo01 getInstance(){
                return s;
        }
}
public class Client{
        public static void main(String []args){
                SingletonDemo01 s=SingletonDemo01.getInstance();
                SingletonDemo01 s2=SingletonDemo01.getInstance();
                System.out.println(s==s2)//结果为true
        }
}
饿汉单例模式代码中,static变量会在装载时初始化,此时也不会涉及到多个对象访问该对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。因此可以省略synchronized关键字。

问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费。

懒汉式实现(单例对象延迟加载)
public class SingletonDemo02{
        private static SingletonDemo02 instance;
        private SingletonDemo02(){}//私有化构造器
        public static synchronized SingletonDemo02 getInstance(){
                if(s==null){
                        s=new SingletonDemo02();
                }
                return s;
        }
}

要点:
-lazy load! 延迟加载,懒加载!真正用的时候才加载!
问题:
-资源利用率高了。但是,每次调用getInstance()方法都要同步,并发效率较低。


双重检测锁实现

这个模式将同步内容下方if到内部,提高了执行的效率,不必每次获取对象是进行同步,只有第一次才同步,创建了以后就没必要了。
public class SingletonDemo03{
        private static SingletonDemo03 instance=null;
        public static SingletonDemo03 getInstance(){
                if(instance==null){
                        SingletonDemo03 ac;
                        synchronized(SingletonDemo03.class){
                                ac=instance;
                                if(ac==null){
                                        synchronized(SingletonDemo03.class);
                                        if(ac==null){
                                                ac=new SingletonDemo03();
                                        }
                                }
                                instance=ac;
                        }
                }
                return instance;
        }
        private SingletonDemo03(){}
}

问题:
由于编译器优化原因和JVM底层内部模型原因,偶尔会出现问题,不建议使用。

静态内部类实现方式(也是一种懒加载方式)
public class SingletonDemo04{
        private static class SingletonClassInstance{
                private static final SingletonDemo04 instance=new SingletonDemo04();                
        }
        public static SingletonDemo04 getInstance(){
                return SingletonClassInstance.instance;
        }
        private SingletonDemo04(){}
}

要点:
外部类没有static属性,则不会像饿汉式那样立即加载对象。
只有真正调用getInstance(),才会加载静态内部类。加载类时是线程安全的。instance是static final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性。
兼备了并发高效调用和延时加载的优势!

使用枚举实现单例模式
public enum SingletonDemo05{
        InSTANCE;
        public void singlrtonOperation(){
        }
}
public static void main(String args[]){
        SingletonDemo05 sd=new SingletonDemo05.INSTANCE;
        SingletonDemo05 sd2=new SingletonDemo05.INSTANCE;
        System.out.println(sd2==sd);
}
优点:
-实现简单
-枚举本身就是单例模式。由于JVM从根本上提供保障!避免通过反射和反序列化的漏洞。
缺点:
-无延迟加载


如何选用五种加载方式
-单例对象 占用资源少,不需要延时加载;
*枚举式 好于  饿汉式
-单例对象 占用资源大,需要延时加载:
*静态内部类式好于懒汉式

问题:
-反射可以破解上面几种(不包含枚举)实现方式!(可以在构造方法中手动抛出异常控制)
-反序列化可以破解上面几种实现方式!
*可以通过定义readResolve()防止获得不同对象
   -反序列化时,如果对象所在类定义了readResolve(),(实际是一种回调),定义返回哪个对象。
public class SingletonDemo01  implements Serializable{
        private static SingletonDemo01 s;
        private SingletonDemo01()throws Exception{
                if(s!=null){
                        throw new Exception("只能创建一个对象");
                }        
        }
        public static synchronized SingletonDemo01 getInstance() throws Exception{
                if(s==null){
                        s=new SingletonDemo01();
                }
                return s;
        }





}
常见的五种单例模式在多线程环境下的效率测试
--相对值
饿汉式           22ms
懒汉式           636ms
静态内部类式     28ms
枚举式           32ms
双重检查锁式     65ms


CountDownLatch
-同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待
countDown() 当前线程调此方法,则级数减一(建议放在finally里执行)
await() 调用此方法会一直阻塞当前线程,直到计数器的值为0


工厂模式:
-实现创建者与调用者的分离
-详细分类:
*简单工厂模式
*工厂方法模式
*抽象工厂模式

面向对象设计的基本原则:
-OCP(开闭原则,Open—Closed Principle):一个软件的实现应当对扩展开放,对修改关闭。
DIP(依赖倒转原则,Dependence Inversion Principle):要针对接口编程,不要针对实现编程。
LOD(迪米特法则,Law of Demeter):置于你直接的朋友通信,而避免和陌生人通信


核心本质:
-实例化对象,用工厂方法代替new操作
-将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

工厂模式:

-简单工厂模式
*用来生产同一等级结构的任意产品.(对于增加新的产品,需要修改已有代码)

-工厂方法模式
*用来生产同一等级结构的固定产品(支持增加任意产品)
-为了避免工厂模式的缺点,不完全满足OCP
-工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个工厂类,二工厂方法模式有一组实现了相同接口的工厂类。

-抽象工厂模式
*用来生产不同产品族的全部产品(对于新的产品无能为力;支持增加产品族)
-抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

根据设计理论建议:工厂方法模式,但实际上,我们一般用简单工厂模式


工厂模式要点
-简单工厂模式(静态工厂模式)
*虽然某种程度不符合设计原则,但实际使用最多
-工厂方法模式
*不修改已有类的前提下,通过增加新的工厂类实现扩展。
-抽象工厂模式
*不可以增加产品,可以增加产品族

应用场景
-JDK中Calendar的getInstance方法
-JDBC中Connection对象的获取
-Hibernate中SessionFactory创建Session
-spring中IOC容器创建管理bean对象
-XML解析式的DocumentBuilderFactory创建解析器对象
-反射中Class对象的newInstance()

建造者模式
本质
-分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责)。从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况下使用。
-由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法,装配算法的解耦,实现了更好的复用。

开发中应用场景
-StringBuilder类的append方法
-SQL中的PreparedStatement
-JDOM中,DomBuilder、SAXBuilder


原型模式prototype
-通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
-就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点。
-优势有:效率高(直接克隆,避免了重新执行构造过程步骤)
-克隆类类似于new,但是不同于new。new创建新的对象属性采用的是默认值。克隆出的对象的属性值完全和原型对象形同。并且克隆出的新对象改变不会影响原型对象。然后在修改克隆对象的值。

原型模式的实现:
-Cloneable接口和clone方法
-prototype模式中实现起来最困难的是内存复制操作,所幸在Java中提供了clone()方法替我们做了绝大部分事情。
@Override
        protected Object clone() throws CloneNotSupportedException {
                Object obj=super.clone();
                return obj;
        }//浅复制

可以利用序列化和反序列化进行深复制
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(s1);
byte[]bytes=bos.toByteArray();
ByteArrayInputStream bis=new ByteArrayInputStream(bytes);
ObjectInputStream ois=new ObjectInputStream(bis);
Sheep s2=(Sheep)ois.readObject();

开发中的应用场景
-原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
Spring中bean的创建实际就是两种:单例模式和原型模式。

创建型模式:都是用来帮助我们创建对象的!
-单例模式
*保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
-工厂模式
*简单工厂模式
  -用来生产同一等级结构的任意产品(对于增加新的产品,需要修改已有代码)
*工厂方法模式
  -用来生产同一等级结构的固定产品(支持增加任意产品)
*抽象工厂模式
  -用来生产不同产品族的产品(对于增加新的产品,无能为力;支持增加产品族)
-建造者模式
*分离了对象组件的单独构造(由Builder来负责)和装配(由Director负责)。从而可以构造出复杂的对象。
-原型模式
*通过new产生一个对象需要非常繁琐的准备或者访问权限,则可以使用原型模式。


结构型模式
-核心作用:是从成簇从结构上实现松耦合,从而扩大整体的类结构,用来解决更大的问题。
-分类:
*适配器模式、代理模式、桥接模式、装饰模式、组合模式、外观模式、享元模式

Adapter模式
-将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
*模式中的角色
-目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
-需要适配器的类(Adaptee):需要适配的类或适配者类
-适配器(Adapter):通过包装成一个需要适配的对象,把原接口转换成目标接口。

类适配器
class Adapter extends Adaptee implements Target{
        public void request(){
                super.specificRequest();
        }
}

对象适配器
class Adapter implements Target{
        private Adapter adaptee;
        public Adapter(Adapter adaptee){
                this.adaptee=adaptee;
        }
        public void request(){
                this.adaptee.specificRequest();
        }
}

工作中的场景
-经常用来做旧系统改造和升级
-如果我们的系统开发之后再也不需要维护,那么很多模式都是没必要的,但是不幸的是,事实却是维护一个系统的代价往往是尅发一个系统的数倍。


我们学习中见过的场景
-java.io.InputStreamReader(InputStream)
-java.io.OutputStreamWriter(OutputStream)

代理模式(Proxy)
-核心作用
*通过代理,控制对象的访问
可以详细的控制访问某个对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。(即 AOP的微观实现)
-AOP(Aspect Oriented Programming面向切面编程)的核心实现

代理模式(Proxy pattern)
-核心角色
*抽象角色
   -定义代理角色和真实角色的公共对外方法
*真实角色
   -实现抽象角色,定义真实角色所要实现的业务逻辑,共代理角色调用。
   -关注真正的业务逻辑
*代理角色
   -实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法实现抽象方法,并可以附加自己的操作。
   -将统一的流程控制放到代理角色中处理!

应用场景:
-安全代理:拼壁对真实角色的直接访问。
-远程代理:通过代理类处理远程方法调用(RMI)
-延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。
  *比如你要开发一个大文档查看软件,大文档中又大的图片,有可能一个图片有100MB,在打开文件时不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开。

分类:
-静态代理(静态定义代理类)

动态代理(dynamic proxy)使用更广泛
-动态代理(动态生成代理类)
*JDK自带的动态代理
*javaassist字节码操作库实现
*CGLIB
*ASM(底层使用指令,可维护性较差)

动态代理相比于静态代理的优点
-抽象角色中(接口)声明的所有方法都被转移到处理器一个集中的方法中处理。这样,我们可以更加灵活和统一的处理众多的方法。
JDK自带的动态代理
-java.lang.reflect.Proxy
  *作用:动态生成代理类的对象
-java.lang.reflect.InvocationHandler(处理器接口)
  *可以通过invoke方法实现对真实角色的代理访问
  *每次通过ProxyStar生成代理类对象时都要指定对应的处理器对象

Star realStar=new RealStar();
StarHandler handler=new StarHandler(realStar);
Star proxy=(Star)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class},handler)
proxy.sing();
//继承InvocationHandler接口,重写invoke方法
@Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // TODO Auto-generated method stub
                Object obj=null;
                if(method.getName().equals("sing")){
                        obj=method.invoke(realStar, args);
                }
                return obj;
        }


桥接模式(bridge)
桥接模式核心要点
-处理多层继承结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。

组合模式(composite)
*使用组合模式的场景
-把部分和整体的关系用树形结构来表示,从而使客户端可以使用同一的方式处理部分对象和整体对象。
*组合模式核心:
-抽象构件(Component)角色:定义了叶子和容器构件的共同点。
-叶子(Leaf)构件角色:无子节点
-容器(Composite)构件角色:有容器特征,可以包含子节点
组合模式工作流程分析(天然的递归)
-组合模式为处理树形结构提供了完美的解决方案,描述了如何将容器红日叶子进行递归组合,使得用户在使用时可以一致性的对待容器和叶子。
-当容器对象的指定方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员,并调用执行。其中,使用了递归调用的机制对整个结构进行处理。

*开发中的应用场景
-操作系统的资源管理器
-GUI的容器层次图
-XML文件解析
-OA系统中,组织结构的处理
-Junit单元框架
  *底层设计就是典型的组合模式,TestCase(叶子),TestUnite(容器)、Test接口(抽象)

装饰模式(decorator)
*职责
-动态的为一个对象增加新的功能
-装饰模式是一种用户代替继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。

实现细节
-Component抽象构件角色
*真实对象有相同的接口。这样,客户端对象就能够以与真实对象相同的方式同装饰对象进行交互。
-ConcreteComponent 具体构件角色(真实对象)
*io流中的FileInputStream、FileOutputStream
-Decorator(装饰角色)
*持有抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能。
ConcreteDecorator 具体装饰角色
*负责给构件对象增加新的责任

开发中使用的场景:
-IO中输入流和输出流的设计
-Swing包中图形界面构件功能
-Servlet API中提供了一个request对象的Decoration设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper类,增强了request对象的功能-Strus2中,request,response,session对象的处理
装饰模式总结:
-装饰模式(Decorator)也叫包装器(Wrapper)模式。
-装饰模式降低系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构件类和具体装饰类可以独立变化,以便增加紫的具体构件类和具体装饰类。
优点
-扩展对象功能,比继承灵活,不会导致个数急剧增加
-可以对一个对象进行多次装饰,创再出不同行为的组合,得到功能更加强大的对象
-具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类。
缺点
-产生很多小对象。大量小对象占据内存,一定程度上影响性能。
-装饰模式易于出错,调试排查比较麻烦。

装饰模式和桥接模式的区别:
-两个模式都是为了解决过多子类对象问题。但他们的诱因不一样。桥接模式是对象自身现有机制沿着多个维度变化,是既有部分不稳定。装饰模式是为了增加新的功能。

外观模式(facade)
外观模式核心:
-为系统提供统一的入口。封装子系统的复杂性,便于客户端调用。
开发中常见的场景
-频率很高。哪里都会遇到。各种技术和框架中,都有外观模式的使用。如:
*JDBC封装的类,commons提供的DBUtils类,各种工具类等等。

享元模式(FlyWeight)
场景:
-内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的对象,我们可以通过享元模式,节省内存。

*核心:
-享元模式以共享的方式高效的支持大量细粒度对象的重用。
-享元对象能做到共享的关键是区分了内部状态和外部状态。
  *内部状态:可以共享,不会随环境变化而改变
  *外部状态:不可以共享,会随环境变化而改变

享元模式实现
-FlyweightFactory享元工厂类
*创建并管理对象,享元池一般设计成键值对
-FlyWeight抽象享元类
*通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态。
-ConcreteFlyWeight具体享元类
*为内部状态提供成员变量进行存储
-UnsharedConcreteFlyWeight非共享享元类
*不能被共享的子类可以设计为非共享享元类

享元模开发中应用的场景:
-享元模式由于其共享的特性,可以在任何“池”中操作,比如:线程池,数据库连接池
-String类的设计也是享元模式

*优点
-极大减少内存中对象的数量
-相同或相似对象内存中只存一份,极大的节约资源
-外部状态相对独立,不影响内部状态
*缺点:
-模式较复杂,使程序逻辑复杂化
-为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态试运行时间变长,用时间换取了空间

行为型模式 关注系统中对象之间的相互交互,研究系统在运行时对象之间的相互通信和协作,进一步明确对象的职责,共有11种模式。

责任链模式
定义:
将能够处理同一类请求的对象连成一条链,所提交的请求沿着联传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象。
*链表模式定义职责链
*非链表方式实现责任链
   -通过集合、数组生成责任链更加实用!实际上,很多项目中,每个具体的Handler并不是有开发团队定义的,而是想目上线后由外部单位加的,所以实用链表方式定义COR链就很困难。

*开发中常见的场景:
—Java中,异常机制就是一种责任链模式。一个try可以对应多个catch,当第一个catch不匹配类型,则自动跳到第二个catch。
—JavaScript语言中,事件的冒泡和捕获机制。Java语言中,事件的处理采用观察者模式—Servlet开发中,过滤器的链式处理
—Struts2中,拦截器的调用也是典型的责任链模式

迭代器模式 iterator
场景:
-提供一种可以便利聚合对象的方式。又被称为:游标cursor模式
-聚合对象:存储数据
-迭代器:遍历数据 
结构:
-聚合对象:存储数据
-迭代器:遍历数据

开发中常见的场景:
-JDK内置的迭代器(List/Set)

中介者模式 Mediator
核心:
-如果一个系统中对象的联系呈现为网状结构,对象之间存在大量多对关系,将导致关系极其复杂,这些对象称之为“同事对象”
-我们可以引入一个中介者对象,使各个同时对象知更中介对象打交道,将复杂的网状结构化解为星型结构。

中介者模式的本质:
—解耦多个同事对象之间的交互关系。每个对象都持有中介者对象的引用,只跟中介者对象打交道。我们通过中介者对象同一管理这些交互关系。

开发中常见的场景:
-MVC模式(其中的C,控制器就是一个中介者对象)
-窗口游戏程序,窗口软件开发中窗口对象也是一个中介者对象
-图形界面开发GUI中,多个组件之间的交互,可以通过引入一个中介者对象来解决,可以是整体的窗口对象或者是DOM对象
-Java.lang.reflect.Method#invoke()

(略)命令模式(command)
*介绍:
-命令模式:将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持撤销的操作。也称之为:动作Action、事务transaction模式

结构:
-Command抽象命令类
-ConcreteCommand具体命令类
-Invoker调用者
*请求的发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此他只与抽象命令类之间存在关联。在程序运行时,将命令对象的execute(),简介调用接受者的相关操作。
-Receiver接收者
*接收者执行与请求相关的操作,具体实现对请求的业务处理。
*未抽象前,实际执行操作内容的对象。
-Client客户类
*在客户类中需要创建调用者对象,在创建具体命令对象时指定对应的接收者。发送者和接收者之间没有直接关系,都是通过命令对象间接调用。

开发中常见的场景:
—Strusts中,action的整个调用过程就有命令模式
—数据库事务机制的底层实现
—命令的撤销和恢复

(略)解释器模式(Interpreter)
介绍:
—是一种不常用的设计模式
—用于描述如何构成一个简单的语言解释器,主要用于使用面向对象语言开发的编译器和解释器设计。
—当我们需要开发一种新的语言时可以考虑解释器模式。

开发中常见的场景:
-EL表达式的处理
-正则表达式解释器
-SQL语法的解释器

访问者模式Visitor
*模式动机:
-对于储存在一个集合中的对象,他们可能具有不同的类型(即使有一个公共的接口),对于该集合中的对象,可以接受一类成为访问者的对象来访问,不同的访问者其访问方式也不同。
定义:
—表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

开发中的场景(应用范围非常窄,了解即可)
-XML文档的解析器设计
-编译器的设计
-复杂集合对象的处理

策略模式 Strategy
-策略模式对应于解决某一个问题的一个算法组,允许用户从该算法族中任选一个算法解决某一问题,同时可以方便的更换算法或者增加新的算法。并且有客户端决定调用哪个算法。
本质:
分离算法,负责实现。
开发中常见的场景:
-JavaSe中GUI编程中,布局管理
-Spring框架中,Resource接口,资源访问策略
-javax.servlet.http.HttpServlet#service()

模板方法模式 template method
-模板方法模式是编程中常用的模式。它定义例如一个操作中的算法骨架,将某些步骤延迟到子类中实现。这样,新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。核心:
-处理某个流程的代码已经都具备,但是某个节点的代码暂时不能确定。因此,我们采用工厂方法模式,将这个节点的代码实现转移给子类完成。即:处理步骤父类中定义好,具体实现延迟到子类中定义

模板方法模式(方法回调或钩子方法)
-好莱坞原则:“Don't call me,we'll call you back”
*在好莱坞,当艺人把简历递交给好莱坞的娱乐公司时,所能做的就是等待,整个过程由娱乐公司控制,演员只能被动地服务安排,在需要的时候再由公司安排具体环节的演出。
-在软件开发中,我们可以讲call翻译为调用。子类不能调用父类,而通过父类调用子类。这些调用步骤已经在父类中写好了,完全由父类控制整个过程。

什么时候用到模板方法模式:
-实现一个算法是,整体步骤很固定。但是,某些部分易变。易变部分可以抽象出来,供子类实现。
开发中常见的场景:
-非常频繁。各个框架、类库中都有他的影子。比如常见的有:
*数据库访问的封装
*Junit单元测试
*Servlet中关于doGet/doPost方法的调用
*Hibernate中模板程序
*spring中JDBCTemplate、HibernateTemplate等。

状态模式state:
核心:
-用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题
结构:
-Context环境类
*环境中维护一个State对象,他是定义了当前的状态
-State抽象类
-ConcreteState具体状态类
*每一个类封装了一个状态对应的行为

开发中常见的场景:
-银行系统中账号状态的管理
-OA系统中公文状态的管理
-酒店系统中,房间状态的管理
-线程对象个状态之间的切换

观察者模式(Observer)广播机制的核心
其主要用于1:N的通知。当一个对象(目标对象Subject或Objservable)的状态变化时,他需要及时告知一系列对象(观察者对象,Observer),令他们做出响应。
-通知观察者的方式:
*推
--每次都会把通知以广播方式发送给所有观察者,所有观察者只能被动地接收
*拉
--观察者只要知道有情况即可。至于什么时候获取内容,获取什么内容,都可以自主决定

JavaSE提供了java.util.Observable和java.util.Observer来实现观察者模式

开发中常见的场景:
-聊天室中,服务器转发给所有客户端
-Servlet中,监听器的实现
-Android中,广播机制
-JDK的AWT中事件处理模式,基于观察者模式的委派事件模型
  *事件源----目标对象
  *时间监听器--观察者

备忘录模式memento
*核心
-就是保存某个对象内部状态的拷贝,这样以后就可以将该对象恢复到原先的状态
*结构:
-源发器类Originator
-备忘录类Memento
-负责人类CareTake
*负责人类
-负责保存好的备忘录对象。
-可以通过增加容器,设置多个“备忘点”
public class CareTaker {
        private EmpMemento memento;
//        private List<EmpMemento>list;

        public EmpMemento getMemento() {
                return memento;
        }

        public void setMemento(EmpMemento memento) {
                this.memento = memento;
        }        
}
备忘点较多时:
将备忘录压栈
public class CareTaker{
        private Memento memento;
        private Stack<Memento>stack=new Stack<Memento>();
}
-将多个备忘录对象,序列化和持久化

开发中常见的应用场景:
—棋类游戏中的悔棋
—普通软件中的撤销操作
—数据库软件中的事务管理的回滚操做
—Photoshop软件中的历史记录
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值