zoukankan      html  css  js  c++  java
  • 设计模式——代理模式与装饰器模式

    代理模式

    解决的问题:在直接访问对象时带来很大的开销。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层

    代理模式就相当于Windows 里面的快捷方式,它并不实现什么功能,而只是在中间加以控制;而装饰器模式为了增强功能。

    Java中的典型示例:静态代理:hibernate中的session.load()方法;动态代理:SpringAOP

    代码实现:

    1> 创建一个接口:Image.java

    public interface Image {
       void display();
    }
    

    2>创建两个接口的实现类

    RealImage.java(假设该类实例化开销很大)

    public class RealImage implements Image {
    
       private String fileName;
    
       public RealImage(String fileName){
          this.fileName = fileName;    
          loadFromDisk(fileName);    // 当实例化RealImage类的时候,会执行这个方法,打印输出语句
       }
    
       @Override
       public void display() {  // 重写父类的display方法
          System.out.println("Displaying " + fileName);
       }
    
       private void loadFromDisk(String fileName){
          System.out.println("Loading " + fileName);
       }
    }
    

    ProxyImage.java(代理类)

    public class ProxyImage implements Image{
    
       private RealImage realImage;
       private String fileName;
    
       public ProxyImage(String fileName){    // 实例化时并不直接实例化RealImage,而是实例化这个类(这样就由类代理了RealImage的display方法)
          this.fileName = fileName;    
       }
    
       @Override
       public void display() {    // 当调用display方法时,实例化RealImage,然后再调用display方法
          if(realImage == null){
             realImage = new RealImage(fileName);
          }
          realImage.display();
       }
    }
    

    3>当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

    public class ProxyPatternDemo {
        
       public static void main(String[] args) {
          Image image = new ProxyImage("test_10mb.jpg");    // 实例化代理类
    
          image.display();       调用方法
       }
    }

    静态代理与动态代理

    静态代理:

    静态代理就是我们上面写的内种方法,它的优缺点也很明显:

    优点:

    代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)。

    缺点:

    1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

    2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如上的代码是只为UserManager类的访问提供了代理,但是如果还要为其他类如Department类提供代理的话,就需要我们再次添加代理Department的代理类。

    即静态代理类只能为特定的接口服务。如想要为多个接口服务则需要建立很多个代理类

    动态代理:

    根据如上的介绍,你会发现每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类

    所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理

    在上面的示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象

    运行时动态的在内存中(那肯定和反射有关)创建代理对象

    好处是:可以不用改动态代理的代码,自动生成要求对象的代理对象

    在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持

    @Test
    public void test1(){
    	//获得动态的代理对象----在运行时 在内存中动态的为Target创建一个虚拟的代理对象
    	//objProxy是代理对象 根据参数确定到底是谁的代理对象
    	TargetInterface objProxy = (TargetInterface) Proxy.newProxyInstance(
    			Target.class.getClassLoader(), //与目标对象相同的类加载器
    			new Class[]{TargetInterface.class}, 
    			new InvocationHandler() {
    				//invoke 代表的是执行代理对象的方法
    				//method:代表目标对象的方法字节码对象
    				//args:代表目标对象的响应的方法的参数
    				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    					System.out.println("目标方法前的逻辑");
    					//通过反射执行目标对象的方法
    					Object invoke = method.invoke(new Target(), args);
    					System.out.println("目标方法后的逻辑");
    					//retrun返回的值给代理对象
    					return invoke;
    				}
    			}
    		);
    	
    	objProxy.method1();
    	String method2 = objProxy.method2();
    	System.out.println(method2);
    	
    }
    

    装饰器模式

    向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

    作用:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

    装饰器模式相当于孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。

    优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

    缺点:多层装饰比较复杂。

    实现步骤:

    1、增强类与被增强的类要实现统一接口

    2、在增强类中传入被增强的类

    3、需要增强的方法重写 不需要增强的方法调用被增强对象的

    示例:解决request.getParameter()方法获取的中文乱码问题

    public class EncodingFilter implements Filter{
    
    	
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    			throws IOException, ServletException {
    		
    		//被增强的对象
    		HttpServletRequest req = (HttpServletRequest) request;
    		//增强对象
    		EnhanceRequest enhanceRequest = new EnhanceRequest(req);
    		
    		
    		chain.doFilter(enhanceRequest, response);
    		
    	}
    
    
    }
    
    class EnhanceRequest extends HttpServletRequestWrapper{		// 1>与要增强的类(HttpServletRequest类)继承/实现同一个类/接口
    	
    	private HttpServletRequest request;
    
    	public EnhanceRequest(HttpServletRequest request) {		// 2>传入要增强的类
    		super(request);
    		this.request = request;
    	}
    	
    	//3>对要增强的方法(getParaameter)重写
    	@Override
    	public String getParameter(String name) {
    		String parameter = request.getParameter(name);//乱码
    		try {
    			parameter = new String(parameter.getBytes("iso8859-1"),"UTF-8");
    		} catch (UnsupportedEncodingException e) {
    			e.printStackTrace();
    		}
    		return parameter;
    	}
    	
    }
    

    两者之间的区别***

    装饰器模式关注于在一个对象上动态的添加方法(可以说他是继承的一个替代方案),然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。

  • 相关阅读:
    判断操作系统多久没有任何操作
    初识类的方法
    类引用
    将窗体显示在 PageControl 上。
    用批处理命令安装打印机
    减小Delphi2010程序的尺寸(关闭RTTI反射机制)
    Delphi 的编码与解码(或叫加密与解密)函数
    c# 让repeater多列显示
    合并动态数组
    [最新]Visual Assist X 破解版下载(10.6.1827)
  • 原文地址:https://www.cnblogs.com/x54256/p/8486706.html
Copyright © 2011-2022 走看看