[2014-05-16]JAVA笔记_设计模式(Design Pattern)

一、  单例模式(Singleton):表示一个类只会生成唯一的一个对象。

//Singelton Pattern

public class SingletonTest{
	public static void main(String args[]){

		Singleton singleton = Singleton.getInstance();
		Singleton singleton2 = Singleton.getInstance();

		System.out.println(singleton == singleton2);
	}
}


class Singleton{

	private static Singleton singleton = new Singleton();
	private Singleton(){	//防止在外部使用new生产对象
		
	}

	public static Singleton getInstance(){
		return singleton;	//static声明的方法是不能调用非static类型声明的属性或方法
	}
}
程序的意义: 永远都只有实例化一个对象。

所谓的单态就是在入口处(构造方法)限制了对象的实例化操作。

总结: 单态设计模式的核心就是将类的构造方法私有化,之后再类的内部产生实例化对象,并通过类的静态方法返回实例化对象的引用。

注意: 对于单例模式(Singleton)来说,如果getInstance()方法中生成Singleton实例则可能会产生同步问题,即可能会产生两个不同的对象。


二、 策略模式(Strategy Pattern)

        概念:1. 定义一组算放,将每个算法都封装起来,并且使他们之间可以互换。 

                     2. 策略模式使这些算法在客户端调用它们的时候能够互不影响的变化。

        意义:1. 策略模式使开发人员能够开发出由许多可替换的部分组成的软件,并且各个部分之间是弱连接的关系。

                    2. 弱连接的特性使软件具有更强大的可扩展性,易于维护;更重要的是,它大大提高了软件的可重用性

        组成:1. 抽象策略角色: 策略类,通常由一个接口或者抽象类实现。

                    2. 具体策略角色: 包装了相关的算法和行为。

                    3. 环境角色: 持有一个策略类的引用,最终给客户端调用的。

        实现:1. 策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立类中,从而使得他们可以相互替换。

                    2. 策略模式使得算法可以在不影响到客户端的情况下发生变化。使用策略莫俄式可以把行为和环境分割开来。

                    3. 环境类负责维持和查询行为类,各种算法则在具体策略中提供。由于算法和环境独立开来,算法的修改都不会影响环境和客户端。

策略模式的编写步骤

                   1. 对策略对象定义一个公共接口。 

                   2. 编写策略类,该类实现了上面的公共接口。

                   3. 在使用策略对象的类中保存一个对策略对象的引用。

                   4. 在使用策略对象的类中,实现对策略对象的 set 和 get 方法(注入)或者使用构造方法完成赋值。

策略模式的缺点

                   1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

                   2. 造成很多的策略类。

解决方案

                  采用工厂方法。


/**
 * 一个包含加、减、乘、除 的策略模式
 */

//抽象策略类
package com.bob.pattern.Strategy;

public interface Strategy {

	public abstract int calculate(int a, int b);
	
}


//环境策略角色:持有一个策略类的引用,最终给客户端调用
package com.bob.pattern.Strategy;

public class Environment {

	private Strategy strategy;		//策略类引用
	
	public Environment(Strategy strategy){		//动态接受子类实例
		this.strategy = strategy;
	}
	
	//操纵属性
	public void setStrategy(Strategy strategy){
		this.strategy = strategy;
	}
	public Strategy getStrategy(){
		return this.strategy;
	}
	
	//或者通过eclipse自动生成:Sourse-->Generate Getters and Setters
	
	//通过传递的strategy来完成实际的比较
	public int calculate1(int a, int b){
		return strategy.calculate(a, b);	//调用接口中的calculate()抽象方法
	}
	
}


//算法:加法
package com.bob.pattern.Strategy;

public class AddStrategy implements Strategy {
	
	@Override
	public int calculate(int a, int b){
		return a + b;
	}
	
}
其余方法略......
package com.bob.pattern.Strategy;

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		AddStrategy addStrategy = new AddStrategy();
		
		Environment environment = new Environment(addStrategy);		//传递一个加法的实例
		
		System.out.println(environment.calculate1(3, 4));
		
		//传递减法实例
		SubtractStrategy subtractStrategy = new SubtractStrategy();
		
		//使用setter方法修改引用
		environment.setStrategy(subtractStrategy);
		
		System.out.println(environment.calculate1(3, 4));
		
	}

}

例子:http://www.open-open.com/lib/view/open1324909543139.html


三、 代理模式 Proxy(Lesson 65)

        代理模式的作用:为其他对象提供一种代理以控制对这个对象的访问。

        代理模式的角色:

               · 抽象角色:声明真实对象和代理对象的公共接口。

               · 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

               · 真实角色: 代理角色所代表的真实对象,是我们最终要引用的对象。


静态代理例子:

package com.bob.proxy;

//抽象角色
public abstract class Subject {

	public abstract void request();
	
}
package com.bob.proxy;

//真实角色
public class RealSubject extends Subject {

	@Override
	public void request() {
		System.out.println("From real subject.");
	}

}
package com.bob.proxy;

//代理角色
public class ProxySubject extends Subject {

	private RealSubject realSubject;	//代理角色内部含有对真实对象的引用
	
	@Override
	public void request() {
		
		//代理对象可以在完成真实对象之前可选的做一些自己需要的操作(收中介费)
		this.preRequest();
		
		if(null == realSubject){
			realSubject = new RealSubject();
		}
		
		realSubject.request();		//真实对象所完成的事情
		
		//完成真实对象之后可选附件操作
		this.postRequest();
		
	}

	private void preRequest(){
		System.out.println("pre request.");
	}
	
	private void postRequest(){
		System.out.println("post request.");
	}
	
}
package com.bob.proxy;

//客户端通过访问代理实现目标
public class Client {

	public static void main(String[] args) {
		
		Subject subject = new ProxySubject();
		
		subject.request();		//调用代理方法
		
	}
}
注意: 如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过 java 的 动态代理类来解决。

动态代理:

       Java的动态代理类位于java.lang.reflect包下,一般主要涉及到2个类:

             (1) Interface InvocationHandler: 该接口中仅仅定义了一个方法。public object invoke(Object proxy, Method method, Object[] args)。在实际使用时,第一个参数 proxy 一般是指代理类,method 是被代理的方法, 如上例中的 request(), args为该方法的参数数组。这个抽象方法在代理类中动态实现。

           每一个代理实例都会有一个与之关联的调用处理器(invocation handler)。 当我们调用一个代理实例上的某一个方法时,这个方法就会被编码并被派发到与之关联的调用处理器它的invoke()方法。

           public object invoke(Object proxy, Method method, Object[] args)。处理代理实例上的一个方法调用,并且将真实结果返回。当一个调用处理器关联到这个调用处理器的某个实例,我们调用这个代理实例上的方法的时候,这个方法就会转移到与这个代理实例所关联的调用处理器的invoke()方法。

                proxy  ---   代理实例。

                method --- 对应于代理实例上接口方法。

                args --- 方法的参数。

         (2) Proxy: 该类即为动态代理类,作用类似于上例中的ProxySubject。  Proxy 提供了一些静态方法用于创建动态代理类和实例,它也是其他动态代理类的一个父类。

                     · protected Proxy(InvocationHandler h): 构造函数,用于给内部的 h 赋值。 

                     · static Class getProxyClass(ClassLoader loader, Class[] interfaces): 获得一个代理类,其中 loader 是类装载器,interfaces 是真实类所拥有的全部接口的数组。

                     ·  public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回代理类的一个实例,返回后的代理类可以当作被代理类使用。(可以理解为使用此方法生成的是一个代理对象,这个代理对象可以代理真实对象完成真实对象的一些操作)。

                             ClassLoader: ---类装载器。创建一个具体的实例的时候是由哪一个类装载器所装载的。

                             Class<?>[] ---  Class类型的接口数组。

                             InvocationHandler ---   需要传递一个InvocationHandler,这个InvocationHandler会传递给它里面的成员变量InvocationHandler。

       · 所谓Dynamic Proxy 是这样一种class:它是在 运行时生成class在生成它时你必须提供一组 Interface 给它, 然后该class 就宣称它实现了这些 Interface。你当然可以把该class的实例当作这些 Interface 中的任何一个来用。当然,这个Dynamic Proxy 其实就是一个 Proxy, 它不会替你做实质性的工作,在生成它的实例时你必须提供一个Handler,由它接管实际的工作。

package com.bob.dynamicproxy;

public interface Subject {

	public void request();
}

package com.bob.dynamicproxy;

public class RealSubject implements Subject {

	@Override
	public void request() {
		// TODO Auto-generated method stub
		System.out.println("From real subject!");	//真实角色
	}

}

package com.bob.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 该代理类的内部属性是Object类型,实际使用的时候通过该类的构造方法传递进来一个对象
 * 此外,该类还实现了invoke方法,该方法中的method.invoke其实就是调用被代理对象的将要
 * 执行的方法,方法参数是sub,表示该方法从属于sub,通过动态代理类,我们可以在执行真实
 * 对象的方法前后加入自己的一些额外方法。
 *
 */
public class DynamicSubject implements InvocationHandler {

	private Object sub;		//真实对象的引用
	
	//通过构造方法给sub赋值
	public DynamicSubject(Object obj){
		
		this.sub = obj;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)	//参数2:调用方法对应的method对象
			throws Throwable {
		
		System.out.println("before calling:" + method);		//完成之前
		
		method.invoke(sub, args);	//Method类的invoke()方法。客户端调用的是request()方法
		//这句话其实相当于静态代理中的 realSubject.request();	只是现在是使用动态代理实现方法调用		
			
		System.out.println("after calling:" + method);		//完成之后
		
		return null;
	}

}

package com.bob.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Client {

	public static void main(String[] args) {
		
		RealSubject realSubject = new RealSubject();	//创建真实对象
		
		InvocationHandler handler = new DynamicSubject(realSubject);	//将真实对象传递给代理
		
		Class<?> classType = handler.getClass();		//获取handler对应的class类
		
		//下面的代码一次性生成代理. newProxyInstance()返回代理类的一个对象,返回后的代理对象可当作真实对象使用。
		//subject对象实现了realSubject.getClass().getInterfaces()这些接口(realSubject实现的接口)。
		Subject subject = (Subject)Proxy.newProxyInstance(classType.getClassLoader(),
					realSubject.getClass().getInterfaces(), handler);

		subject.request();	//subject只是一个代理,当调用方的时候流程就立刻转到了handler里面的动态代理类的invoke()方法。看第二段红色字体
		
		System.out.println(subject.getClass());
		
		
	}
}

动态代理步骤:

       1. 创建一个实现接口 InvocationHandler 的类,它必须实现 invoke 方法;

       2. 创建被代理的类以及接口;

       3. 通过 Proxy 的静态方法 newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandel h) 创建一个地代理;

       4. 通过代理调用方法。

























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值