您的位置:首页 > 编程语言 > Java开发

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中关于设计模式的总结”是我在学习设计模式以及实际应用中的个人学习笔记,今天把她晒出来,希望与大家一起分享,如果哪里写的不好,还望多多指教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息