设计模式-结构型模式讲解下(装饰者外观代理)

Posted 小毕超

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-结构型模式讲解下(装饰者外观代理)相关的知识,希望对你有一定的参考价值。

一、结构型设计模式

上篇,我们讲解了结构型设计模式的适配器、桥接、组合、享元模式。

文章地址:https://blog.csdn.net/qq_43692950/article/details/120248267

这篇文章我们讲解下 结构型设计模式的装饰者、外观、代理模式。

二、装饰者模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。它是作为现有的类的一个包装。
装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

举个例子:还是用上篇文章例子中的绘画不同的形状的例子,加入系统中有画各种形状的功能,但随着功能后期的演化,需要画出带有边框的各种形状,那么此时就可以采用装饰者设计模式来做增强。

下面使用程序演示下上面的例子:

  1. 定义形状接口
public interface Shape {
   void draw();
}
  1. 定义圆形的实现
public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("开始画圆形!");
   }
}
  1. 定义矩形的实现
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("开始画矩形!");
   }
}
  1. 定义装饰器的抽象模板
public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;
 
   public ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
   }
 
   @Override
   public void draw(){
      decoratedShape.draw();
   }  
}
  1. 定义具体的边框装饰器
public class BorderShapeDecorator extends ShapeDecorator {
 
   public BorderShapeDecorator(Shape decoratedShape) {
      super(decoratedShape);     
   }
 
   @Override
   public void draw() {
      decoratedShape.draw();         
      setRedBorder(decoratedShape);
   }
 
   private void setRedBorder(Shape decoratedShape){
      System.out.println("画边框!");
   }
}
  1. 演示
public class demo {
   public static void main(String[] args) {
      Shape circle = new Circle();
      circle.draw();

      Shape shape = new BorderShapeDecorator(new Circle());
      shape.draw();

      Shape shape1 = new BorderShapeDecorator(new Rectangle());
      shape1.draw();
   }
}


上面可以看出再不改变原先类的基础上,做了画边框的效果,对原有做增强,使用装饰者设计模式,可以大大提高系统的可扩展性。

三、外观模式

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。它向现有的系统添加一个接口,来隐藏系统的复杂性。
这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
它的优点是可以减少系统相互依赖、提高灵活性、提高了安全性。但是它不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

举个例子:还是画各种图形的例子,比如要画圆形、矩形、三角形,没画一种图像都要拿到对应的抽象,并调用绘制方法,如果要画的形状过多,这么多的抽象就不好管理了,而如果使用外观设计模式,提供一个统一的抽象,在这个抽象中就可以完成上面不同的绘制,这样就方便了我们的管理。

下面使用程序演示下上面的例子:

  1. 定义形状的接口
public interface Shape {
   void draw();
}
  1. 定义圆形的实例
public class Circle implements Shape {

    @Override
    public void draw() {
        System.out.println("开始画圆!");
    }
}
  1. 定义矩形的实例
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("开始画矩形!");
   }
}
  1. 定义三角形的实例
public class Triangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("开始画三角形!");
   }
}
  1. 定义一个外观类,并调用上面的功能
public class ShapeFacade {
   private Shape circle;
   private Shape rectangle;
   private Shape square;
 
   public ShapeFacade() {
      circle = new Circle();
      rectangle = new Rectangle();
      square = new Triangle();
   }
 
   public void drawCircle(){
      circle.draw();
   }
   public void drawRectangle(){
      rectangle.draw();
   }
   public void drawSquare(){
      square.draw();
   }
}
  1. 演示
public class demo {
   public static void main(String[] args) {
      ShapeFacade shapeFacade = new ShapeFacade();
      shapeFacade.drawCircle();
      shapeFacade.drawRectangle();
      shapeFacade.drawSquare();
   }
}


外观设计模式还是比较容易理解的,就是把多个功能统一整个到一个对象中,由这个对象再去调用具体的类和方法。

四、代理设计模式

通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或调用后处理。既(AOP微实现) 。

代理有分静态代理和动态代理,静态代理就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。而动态代理是在我们使用时,动态的生成代理对象,他是在内存中构建代理对象的。

举个例子,在做数据库操作时,一般我们都会在事物中做SQL的操作,那就需要在操作前开启事物,操作后如果成功就需要提交事物,如果代用代理设计模式,就可以将事物开启提交逻辑放在代理类中,被代理的类,只需要关注业务逻辑即可。

我们以支付和事物为例演示下,代理模式

1. 采用静态代理,实现上面例子

  1. 定义支付接口
public interface PayInterFace {
    void pay();
}
  1. 定义微信支付实现
public class WxPay implements PayInterFace {
    @Override
    public void pay() {
        System.out.println("支付中...");
    }
}
  1. 定义支付的代理类
public class PayProxy implements PayInterFace {
    private WxPay pay;

    public PayProxy(WxPay pay) {
        this.pay = pay;
    }

    @Override
    public void pay() {
        System.out.println("事物开始!");
        pay.pay();
        System.out.println("提交事物!");
    }
}
  1. 演示
public class demo {
    public static void main(String[] args) {
        PayInterFace pay = new PayProxy(new WxPay());
        pay.pay();
    }
}


上面的静态代理,可以看出,我们需要对每个被代理对象设计一个代理类,如果代理的功能非常多,那就需要开发人员写特别多的代理类,下面可以看下动态代理的使用。

2. 采用动态代理,实现上面例子

这里使用JDK自带的动态代理来实现

  1. 还是上面的例子,我们再定义一个支付宝的支付实现
public class ZfbPay implements PayInterFace {
    @Override
    public void pay() {
        System.out.println("支付宝支付中...");
    }
}
  1. 定义代理对象,采用jdk的 InvocationHandler 接口
public class PayProxy implements InvocationHandler {

    private Object object;

    public PayProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("事物开始!");
        Object result = method.invoke(object, args);
        System.out.println("提交事物!");
        return result;
    }
}
  1. 演示
public class demo {
    public static void main(String[] args) {
        PayInterFace pay = (PayInterFace) Proxy.newProxyInstance(
                PayInterFace.class.getClassLoader(),
                new Class[]{PayInterFace.class},
                new PayProxy(new WxPay()));
        pay.pay();


        PayInterFace pay1 = (PayInterFace) Proxy.newProxyInstance(
                PayInterFace.class.getClassLoader(),
                new Class[]{PayInterFace.class},
                new PayProxy(new ZfbPay()));
        pay1.pay();

    }
}


上面使用一个代理类,代理了多个对象,相对于静态代理,是代码更简介,灵活性也更高。

以上是关于设计模式-结构型模式讲解下(装饰者外观代理)的主要内容,如果未能解决你的问题,请参考以下文章

设计模式-行为型模式讲解一(责任链命令迭代器)

设计模式结构型(代理模式桥接模式装饰者模式适配器模式)

设计模式----结构型模式之代理模式和装饰者模式的区别

软件设计模式

23种设计模式Java版第三篇

设计模式之美学习-结构型-装饰者模式(二十)