Java程序设计模式程序设计.doc
Java设计模式1.1 创建型模式AbstractFactory ( 抽象工厂 ) FactoryMethod ( 工厂方法 ) Singleton ( 单态模式 ) Builder ( 建造者模式 ) Prototype ( 原型模式 ) 1.2 结构型模式Adapter ( 适配器模式 ) Bridge ( 桥接模式 ) Composite ( 组合模式 ) Decorator ( 装配模式 ) Facade ( 外观模式 ) Flyweight ( 享元模式 ) Proxy ( 代理模式 ) 1.3 行为型模式Chain of Responsibility ( 责任链模式 ) Command ( 命令模式 ) Interpreter ( 解释器模式 ) Iterator ( 迭代器模式 ) Mediator ( 中介者模式 ) Memento ( 备忘录模式 ) Observer ( 观察者模式 ) State ( 状态模式 ) Strategy ( 策略模式 ) TemplateMethod ( 模板方法 ) Visitor ( 访问者模式 ) Toney Chen的总结Singleton设计模式 Singleton单类模式是最简单的设计模式,它的主要作用是保证在程序运行生命周期中,使用了单类模式的类只能有一个实例对象存在。单类模式实现了类似C语言中全局变量的功能,单类模式常用于注册/查找的服务。单类模式有两种实现方式:饱汉模式和饿汉模式,如下:饱汉单类模式例子代码:java view plaincopy1. public class Singleton1 2. /饱汉模式,声明时就创建实例对象 3. public static final Singleton1 instance = new Singleton1(); 4. /单类模式的构造方法必须为private,以避免通过构造方法创建对象实例, 5. /并且必须显示声明构造方法,以防止使用默认构造方法 6. private Singleton1() 7. /单类模式必须对外提供获取实例对象的方法 8. public static Singleton1 geInstance() 9. return instance; 10. 11. 饿汉单类模式即延迟初始化单类方式,例子代码:java view plaincopy1. public class Singleton2 2. /饿汉模式,声明时不创建实例对象 3. public static Singleton2 instance; 4. /单类模式的构造方法必须为private,以避免通过构造方法创建对象实例, 5. /并且必须显示声明构造方法,以防止使用默认构造方法 6. private Singleton2() 7. /单类模式必须对外提供获取实例对象的方法,延迟初始化的单类模式必须使用synchronized同步关键字,否则多线程情况下很容易产生多个实例对象 8. public static synchronized Singleton2 geInstance() 9. /延迟初始化,只有当第一次使用时才创建对象实例 10. if(instance = null) 11. return new Singleton2(); 12. 13. return instance; 14. 15. 一般认为饱汉模式要比饿汉模式更加安全。上面两种Singleton单类设计模式的实现方式都隐藏有如下的问题:(1).虽然构造方式的访问修饰符为private,即除了自身以外其他任何类都无法调用,但是通过反射机制的setAccessiable(true)方法可以访问私有方法和属性。因此Singleton单类模式必须考虑这种例外情况。(2).对象序列化之后再反序列化时会生成新的对象,因此当Singleton单类模式类实现序列化接口时,必须显式声明所有的字段为tranisent。在JDK1.5之后引入了Enum枚举,因此在JDK1.5之后Singleton单类模式又有了第三种实现方式,也是最好的实现方式,例子如下:java view plaincopy1. public enum Singleton3 2. INSTANCE 3. public void doSomething() 4. 5. 6. 7. public Singleton3 getInstance() 8. return INSTANCE; 9. 10. public abstract void doSomething(); 11. Singleton单类模式中只有一个INSTANCE枚举元素,枚举可以保证真个程序生命周期中只有一个实例对象存在,同时还避免了常规Singleton单类模式private构造方法被反射调用和序列化问题。注意:java中除了构造方法可以创建对象实例以外,还可以通过克隆方法(clone()是Object中的protected方法)来创建对象, 若单类对象直接继承自Object对象,则如果没有提供具体clone方法实现,则当调用克隆方法创建对象时,会抛出运行时的异常 CloneNotSupportedException。若单类类继承了实现克隆方法的类,则在单类类中必须覆盖父类的克隆方法,显式抛出异常CloneNotSupportedException。另外,实现了单类模式的类不能再有派生子类,因为构造方式是私有的,子类无法调用父类构造方法,因此达到了Final的效果。Proxy设计模式 Proxy代理设计模式是一种控制对象访问的设计模式,类似于网络代理,网络代理机制如下图:Proxy代理设计模式机制如下:客户端程序通过代理程序来访问真正的目标程序,代理程序对外隐藏了目标程序。普通代理设计模式例子代码如下:java view plaincopy1. interface ProxyBase 2. public void f(); 3. public void g(); 4. public void h(); 5. 6. /代理程序 7. class Proxy implement ProxyBase 8. private ProxyBase implementation; 9. public Proxy() 10. /目标程序 11. implementation = new ProxyImplementation(); 12. 13. public void f() 14. implementation.f(); 15. 16. public void g() 17. implementation.g(); 18. 19. public void h() 20. implementation.h(); 21. 22. 23. /目标程序 24. class ProxyImplementation implements ProxyBase 25. public void f() 26. System.out.println(“ProxyImplementation.f()”); 27. 28. public void g() 29. System.out.println(“ProxyImplementation.g()”); 30. 31. public void h() 32. System.out.println(“ProxyImplementation.h()”); 33. 34. 35. /客户端程序调用代理 36. public class ProxyDemo 37. public static void main(String args) 38. /客户端调用代理程序 39. Proxy p = new Proxy(); 40. p.f(); 41. p.g(); 42. p.h(); 43. 44. 从JDK1.3以后,java引入动态代理机制,java的动态代理只能针对接口进行动态代理,即要实现动态代理的类必须实现接口,CGLIB提供了针对类的动态代理功能。JDK动态代理的例子如下:java view plaincopy1. /代理接口 2. interface Foo 3. public void f(String s); 4. public void g(int i); 5. public void h(int i, String s); 6. 7. /接口实现类,即被代理类 8. class FooImpl implements Foo 9. public void f(String s) 10. System.out.println(“FooImpl.f(), s=” + s); 11. 12. public void g(int i) 13. System.out.println(“FooImpl.g(), i=” + i); 14. 15. public void h(int i, String s) 16. System.out.println(“FooImpl.h(), i=” + i + “, s=” + s); 17. 18. 19. /动态代理处理类 20. class ProxyHandler implements InvocationHandler 21. /代理实现类 22. private Object delegate; 23. public ProxyHandler (Object obj) 24. delegate = obj; 25. 26. public Object invoke(Object proxy, Method method, Object args) 27. System.out.println(“Before mothod:” + method); 28. method.invoke(this.delegate, args); 29. System.out.println(“After mothod:” + method); 30. return null; 31. 32. 33. public class DynamicProxyDemo 34. public static void main(String args) 35. Foo foo = new FooImpl(); 36. ProxyHandler handler = new ProxyHandler(foo); 37. /产生动态代理 38. Foo proxy = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(), new ClassFoo.class, handler); 39. proxy.f(“f”); 40. proxy.g(1); 41. proxy.h(“h”, 2); 42. 43. 动态代理和普通的代理模式的区别:动态代理中的代理类是由java.lang.reflect.Proxy类在运行期时根据接口定义,采用Java 反射功能动态生成的。和java.lang.reflect.InvocationHandler结合,可以加强现有类的方法实现。动态带来自定义 Handler实现InvocationHandler接口,自定义Handler实例化时,将代理的实现类传入自定义Handler对象中。自定义 Handler需要实现invoke方法,该方法可以使用Java反射调用实现类的实现的方法,同时当然可以实现其他功能,例如在调用实现类方法前后加入 Log,实现安全认证等。而Proxy类根据Handler和需要代理的接口动态生成一个接口实现类的对象。当用户调用这个动态生成的实现类时,实际上是 调用了自定义Handler的invoke方法。State设计模式 State状态设计模式类似于Switch多路分支功能的开关,State状态模式机制如下:State状态设计模式用于改变对象的行为,在代理的生命周期里,随着状态变化从一个目标实现程序切换到另一个目标实现程序。我们经常遇到如下的程序代码:java view plaincopy1. public class Creature 2. private Boolean isFrog = true;/标识 3. public void greet() 4. if(isForg) 5. System.out.println(“Ribbet!”); 6. else 7. System.out.println(“Darling!”); 8. 9. 10. /转换标识 11. public void kiss() 12. isForg = false; 13. 14. public static void main(String args) 15. Creature creature = new Creature(); 16. creature.greet(); 17. creature.kiss(); 18. creature.greet(); 19. 20. 上面例子代码中greet()方法在执行具体操作之前必须要判断一下标识,代码显得笨拙繁琐,使用简单State状态模式改写上面代码如下:java view plaincopy1. public class Creature 2. /状态接口 3. private interface State 4. String response(); 5. 6. private class Forg implements State 7. public String response() 8. return “Ribbet!”; 9. 10. 11. private class Prince implements State 12. public String response() 13. return “Darling!”; 14. 15. 16. private State state = new Forg(); 17. public void greet() 18. System.out.println(state.response); 19. 20. public void kiss() 21. state = new Prince(); 22. 23. public static void main(String args) 24. Creature creature = new Creature(); 25. creature.greet(); 26. creature.kiss(); 27. creature.greet(); 28. 29. State状态设计模式中,状态自动切换并传播,不需要再改动标识,代码显得非常优雅。State状态设计模式一个基本框架如下:java view plaincopy1. /状态接口 2. interface State 3. void operation1(); 4. void operation2(); 5. void operation3(); 6. 7. /状态实现类1 8. class implementation1 implements State 9. public void operation1() 10. System.out.println(“Implementation1.operation1()”); 11. 12. public void operation2() 13. System.out.println(“Implementation1.operation2()”); 14. 15. public void operation3() 16. System.out.println(“Implementation1.operation3()”); 17. 18. 19. /状态实现类2 20. class implementation2 implements State 21. public void operation1() 22. System.out.println(“Implementation2.operation1()”); 23. 24. public void operation2() 25. System.out.println(“Implementation2.operation2()”); 26. 27. public void operation3() 28. System.out.println(“Implementation2.operation3()”); 29. 30. 31. /服务提供者 32. class ServiceProvider 33. private State state; 34. public ServiceProvider(State state) 35. this.state = state; 36. 37. /状态更改 38. public void changeState(State newState) 39. state = newState; 40. 41. public void service1() 42. / 43. state.operation1(); 44. / 45. state.operation3(); 46. 47. public void service2() 48. / 49. state.operation1(); 50. / 51. state.operation2(); 52. 53. public void service3() 54. / 55. state.operation3(); 56. / 57. state.operation2(); 58. 59. 60. public class StateDemo 61. private ServiceProvider sp = new ServiceProvider(new Implementation1(); 62. private void run(ServiceProvider sp) 63. sp.service1(); 64. sp.service2(); 65. sp.service3(); 66. 67. public static void main(String args) 68. StateDemo demo = new StateDemo(); 69. demo.run(sp); 70. sp.changeState(new Implementation2(); 71. demo.run(sp); 72. 73. State状态模式和Proxy代理模式都为客户端程序提供了一个目标程序代理,真正的目标程序被代理所隐藏,当客户端程序调用目标程序时,首先将调用请求发送给代理,代理才真正调用目标程序,但是Proxy代理模式和State状态模式有如下区别:(1).Pro xy代理模式中被调用的目标程序只有一个,而State状态模式中被调用的目标程序有多个。(2).Proxy代理模式的目的是控制客户端对目标程序的访问,而State状态模式是为了根据条件动态改变目标程序。Itrator设计模式 Iterator迭代器模式,提供一种统一的方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节,迭代器模式是为容器而设计。程序对容器对象的访问必然涉及到遍历算法,不同的容器遍历算法是不同的,List,Stack和Set等等常用容器遍历元素的算法各不相同。解决容 器遍历算法差异有两种方案:第一,可以将遍历方法塞到容器对象中去,容器承受了过多的功能,它不仅要负责自己“容器”内的元素维护(添加、删除等等),而 且还要提供遍历自身的接口;第二,根本不提供容器遍历算法,让容器使用者自己去实现。该方法虽然是省事,却又将容器的内部细节暴露无遗。 迭代器模式的出 现,很好的解决了上面两种情况的弊端,不但将遍历容器的算法从不同集合容器类中抽象出来,同时又对外隐藏了容器的具体实现细节。迭代器模式由以下角色组成: 1) 迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的接口。 2) 具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。 3) 容器角色(Container):容器角色负责提供创建具体迭代器角色的接口。 4) 具体容器角色(Concrete Container):具体容器角色实现创建具体迭代器角色的接口这个具体迭代器角色于该容器的结构相关。 Java集合框架中迭代设计模式的应用:java view plaincopy1. /迭代器 ,该接口提供了迭代遍历的通用方法 2. public interface Iterator 3. boolean hasNext(); 4. Object next(); 5. void remove(); 6. 7. /容器迭代化接口,凡是实现此接口的集合容器距可以生成相应的迭代器 8. public interface Iterable<T> 9. /产生迭代器,将容器对象转换为迭代器对象 10. Iterator<T> interator(); 11. 12. /java集合框架的根接口,该接口继承了容器迭代化接口,因此java中的集合都可以被迭代 13. public interface Collection<E> extends Iterable<E> 自定义迭代器,以ArrayList为自定义迭代容器的底层数据结构,实现自定义迭代器的代码如下:java view plaincopy1. public class MyIterator implements Iterable 2. /存放数据的集合 3. private ArrayList list; 4. /负责创建具体迭代器角色的工厂方法 5. public Iterator iterator() 6. return new Itr(list); 7. 8. /作为内部类的具体迭代器角色 9. private class Itr implements Iterator 10. ArrayList myList; 11. int position = 0; 12. public Itr(ArrayList list) 13. this.myList = list; 14. 15. public Object next() 16. Object obj = myList.get(position); 17. position+; 18. return obj; 19. 20. public boolean hasNext() 21. if (position >= myList.size() 22. return false; 23. else 24. return true; 25. 26. 27. /不支持remove操作 28. public void remove() 29. throw new UnsupportedOperationException( 30. "Alternating MyIterator does not support remove()"); 31. 32. 33. 使用时,MyIterator对象直接调用iterator()方法就可以将自定义容器对象转换为迭代器对象。Iterator模式的优点:(1).实现功能分离,简化容器接口。让容器只实现本身的基本功能,把迭代功能委让给外部类实现,符合类的设计原则。(2).隐藏容器的实现细节。(3).为容器或其子容器提供了一个统一接口,一方面方便调用;另一方面使得调用者不必关注迭代器的实现细节。(4).可以为容器或其子容器实现不同的迭代方法或多个迭代方法。Strategy设计模式 Strategy策略设计模式主要是定义一系列的算法,把这些算法封装成单独的类,在运行时动态选择需要的算法,策略模式机制如下:策略模式例子如下:java view plaincopy1. /文本替换策略 2. abstract class TextStrategy 3. protected String text; 4. 5. public TextStrategy(String text) 6. this.text = text; 7. 8. public abstract String replace(); 9. 10. /替换算法1:将文本中"rn"替换为"n" 11. class StrategyOne extends TextStrategy 12. public StrategyOne(String text) 13. super(text); 14. 15. public String replace() 16. System.out.println(“StrategyOne:”); 17. String result = text.replaceAll("rn", "n"); 18. return result; 19. 20. 21. /替换算法2:将文本中"n"替换为"rn" 22. class StrategyTwo extends TextStrategy 23. public StrategyTwo(String text) 24. super(text); 25. 26. public String replace() 27. System.out.println(“StrategyTwo:”); 28. String result = text.replaceAll(“n", "rn"); 29. return result; 30. 31. 32. public class TextCharChange 33. public static void replace(TextStrategy strategy) 34. strategy.replace(); 35. 36. public static void main(String args) 37. String testText1 = "This is a test text!n Oh! Line Return!n" 38. String testText2 = This is a test text!rn Oh! Line Returnrn" 39. TextCharChange.replace(new StrategyOne(testText2); 40. TextCharChange.replace(new StrategyTwo(testText1); 41. 42. State状态模式和Strategy策略模式非常类似,但是有如下区别:(1).State状态模式重点在于设定状态变化,根据状态,返回相应的响应。(2).Strategy策略模式重点在于根据需求直接采用设定的策略,即根据场景选择合适的处理算法,而不需要改变状态。Factory设计模式 Factory工厂设计模式为创建对象提供了一种抽象,而对使用者屏蔽了对象创建的具体细节过程,工厂模式有三种:简单工厂模式,抽象工厂模式和工厂方法模式。(1).简单工厂模式