java中关于设计模式的总结
2013-11-24 10:33
465 查看
java中关于设计模式的总结
1.单例模式:单列模式就是调用该单例类的方法所获得的对象始终是唯一的。
eg:
public class Foo { private static Foo instance = new Foo(); private Foo() {} public static Foo getInstance() { return instance; } }
或:
public class Foo { private static Foo instance; private Foo() {} public static Foo getInstance() { if(instance == null){ instance = new Foo(); } return instance; } }
单例模式中类的特点:
--构造方法私有:外界无法创建对象
--包含一个静态的该类成员:该类只会有唯一的实例
--通过一个静态方法返回该成员:外界通过该方法获得实例,无论调用多少次该方法,获得的是同一个实例。
常见的单列模式有JDBC中的Connection对象、Hibernate中的SessionFactory对象。
eg:线程单例(单例模式的特例):
public class Foo { private static ThreadLocal<Foo> tl = new ThreadLocal<Foo> (); private Foo() {} public static Foo getInstance() { Foo foo = tl.get(); if(foo==null) { foo = new Foo(); tl.set(foo); } return foo; }
2. 简单工厂:
简单工厂模式用于根据不同情况生成一个合适的子类对象。通常是一个抽象类被多个子类所继承,在抽象类中通过静态方法根据不同情况获得不同的子类对象(对象的编译时类型一致,均为父类类型)
eg:
public abstract class Foo { public static Foo getIntance(..) { //根据参数或者特定情况,返回一个合适的子类对象 //在不同的情况下使用不同的子类对象。 //该逻辑被一个静态方法封装。 //对外而言是透明的 } }
public class FooSub1 extends Foo {} public class FooSub2 extends Foo {} ... ... ....
一个最常见的列子就是Calendar类,中获取Calendar对象。
Calendar cal = Calendar.getInstance();
Calendar类中getInstance()方法如下:
public static Calendar getInstance(Locale aLocale) { Calendar cal = createCalendar(TimeZone.getDefaultRef(), aLocale); cal.sharedZone = true; return cal; } ........... if ("th".equals(aLocale.getLanguage()) && ("TH".equals(aLocale.getCountry()))) { return new sun.util.BuddhistCalendar(zone, aLocale); } else if ("JP".equals(aLocale.getVariant()) && "JP".equals(aLocale.getCountry()) && "ja".equals(aLocale.getLanguage())) { return new JapaneseImperialCalendar(zone, aLocale); } // else create the default calendar return new GregorianCalendar(zone, aLocale); }
还有比如windows自带的画板,如果把画笔的笔头看做是一个抽象类的话,则钢笔头、铅笔头、粗笔头、就是一个个具体的实现子类。
3.策略模式:
策略模式就是一个抽象类有多个继承子类,或者一个接口有多个实现子类。其中,具体的继承子类或者实现子类就是策略类。在应用时,可以根据不
同的子类或实现类实现不同的方法和作用。也可以把策略模式看成是简单 工程模式。
eg:
public abstract class Bar { } public class BarSub1 extends Bar { //加密算法一 } public class BarSub2 extends Bar { ////加密算法二 } .....
比如,我们要实现加密算法,而加密算法可以有多个。
4.回调模式:
如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法。通常需要使用匿名内部类实现。在回调模式中传入的参数不是一个数据,而是一段逻辑代码(或者说是某种方法)
public void f(String str1) {...} public void g(CallBack cb) {...} interface CallBack { public void k(); } g(new CallBakc{}{ public void k() { ... .... .... } });
比如之前用到的TimerTask定时器:
import java.util.Timer; import java.util.TimerTask; public class Test { public static void main(String[] arg) { Timer timer = new Timer(); timer.schedule(new TimerTask() { StringBuilder buf = new StringBuilder(); int i = 1; public void run() { //匿名内部类 buf.append(i); i++; Test i = new Test(); System.out.println(buf.toString()); } }, 1000, 1); } }
还有Swing中的事件监听机制:比如给一个按钮添加一个事件:
btn.addActionListener(ActionListener listener); btn.addActionListener( new ActionListener() { public void actionPerformed(...) {...} } );
还有对数组和集合的自定义排序:eg:
Dog[] dogs = ... Arrays.sort(dogs, Comparator c)
5.包装模式(Wapper):
包装模式是代理模式的一种特列。
public interface Foo { public void f1(); public void f2(); public void f3(); ... ... .... }
public class FooImpl implements Foo { public void f1() { ... ... .... } public void f2() { ... ... .... } public void f3() { ... ... .... } }
public class FooWrapper implements Foo { private Foo impl = ... public void f1() { impl.f1(); } public void f2() { impl.f2(); } public void f3() { impl.f3(); } }
class XXXFooWrapper extends FooWrapper { public void f1() { ... ... ... } }
包装模式的应用非常多,比如jdbc中线程池对Connection对象的管理,从线程中获取的Connection对象是被线程池包装过的,其所有方法均在包装类中进行重写,除了close()方法外,在包装类中其他的方法均是直接调用原方法,而close()方法的功能并不是关闭连接,而是把连接还回连接池。
Connection con = ds.getConnection();
con.close();//这里面的close方法并未中正的关闭连接,只是把连接还回连接池。
还有对非线程安全的集合改造成线性安全的集合的Collections.synchronizedXXX()方法
eg:java中通过Collections.synchronizedMap(HashMap)方法将非线程安全的集合(比如HashMap)改造成线程安全集合的源代码剖析如下:
Map<String,Strudent> map1 = new HaspMap<String,Student>();
Map<String,Strudent> map2 = Collections.synchronizedMap(map1);
其内部的实现机制是通过包装模式来设计的,其中synchronizedMap()的put()方法实现代码如下:
Collections类中synchronizedMap方法如下,由源码可知,synchronizedMap方法返回了一个SynchronizedMap类的实例
public class Collections { public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) { return new SynchronizedMap<K,V>(m); } ........... }SynchronizedMap类源码如下:
private static class SynchronizedMap<K,V>implements Map<K,V>, Serializable { // use serialVersionUID from JDK 1.2.2 for interoperability private static final long serialVersionUID = 1978198479659022715L; //将put方法加上同步锁 public V put(K key, V value) { synchronized(mutex) {return m.put(key, value);} } ......... }
6.代理模式:
代理模式通常有一个业务接口,下面有一个业务实现类和一个代理类,在代理类中调用了业务实现类中的方法,同时加入了额外的处理方法。
比如一个很常见的应用就是struts中对el表达式中的getAttribute()方法的改写。
比如在Action中定义了属性private String name;
在jsp页面上可以直接通过${name}的到对应的值。
按理说,EL表达式取数据的对象只有pageContext,request,session,application四类,不应该从Action对象中取name属性值,但struts框架重新包装了request,getAttribute()方法被改写(request的其他方法没 被改写),如果从request对象中调用getAttribute()方法没获取到值(null),那么会自动从action中取,这样,struts中EL表达式就可以直接获取到Action属性中的值了。
这就是用到了代理模式,其实现源码参考参考如下:
public class StrutsRequestWrapper extends HttpServletRequestWrapper{ //重写 public Object getAttribute(String key){ //寻找原request信息 Object obj = super.getAttribute(key); if(obj == null){ //寻找valuestack信息 obj = valuestack.findValue(key); //Ognl.getValue(key,context,root); } return obj; } }其中获取name属性值的访问顺序如下:
${name} -->request.getAttribute("name")-->Ognl.getValue("name",context,root)
如果不熟悉struts中获取属性值的原理,可以参看:http://blog.csdn.net/zhu_xun/article/details/16868525,这里面说的很详细。
代理模式的应用还有hibernate中的延迟加载,和Spring中的AOP机制(事务控 制)。
以上的“java中关于设计模式的总结”是我在学习设计模式以及实际应用中的个人学习笔记,今天把她晒出来,希望与大家一起分享,如果哪里写的不好,还望多多指教。
相关文章推荐
- 【设计模式】24种设计模式总结
- 设计模式关系总结
- 设计模式总结
- java重写和重载
- 深入理解java的多态性
- 好的教程推荐
- HashMap源码分析(基于JDK1.6)
- [Java] 多态-01
- [Java] 多态-01
- java继承实例基础
- struts2的s:iterator 标签 详解
- eclipse 自动生成代码注释template
- Java 中的接口有什么作用?
- [Java] 对象转型-02
- [Java] 对象转型-02
- myeclipse 10 反编译插件 安装
- Eclipse 配置struts2图解
- java JCombobox和JList的使用
- SVN服务器搭建以及在MyEclipse中的使用方法
- Ubuntu下eclipse开发hadoop应用程序环境配置