设计模式-结构型模式讲解下(装饰者外观代理)
Posted 小毕超
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-结构型模式讲解下(装饰者外观代理)相关的知识,希望对你有一定的参考价值。
一、结构型设计模式
上篇,我们讲解了结构型设计模式的适配器、桥接、组合、享元模式。
文章地址:https://blog.csdn.net/qq_43692950/article/details/120248267
这篇文章我们讲解下 结构型设计模式的装饰者、外观、代理模式。
二、装饰者模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。它是作为现有的类的一个包装。
装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
举个例子:还是用上篇文章例子中的绘画不同的形状的例子,加入系统中有画各种形状的功能,但随着功能后期的演化,需要画出带有边框的各种形状,那么此时就可以采用装饰者设计模式来做增强。
下面使用程序演示下上面的例子:
- 定义形状接口
public interface Shape {
void draw();
}
- 定义圆形的实现
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("开始画圆形!");
}
}
- 定义矩形的实现
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("开始画矩形!");
}
}
- 定义装饰器的抽象模板
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
@Override
public void draw(){
decoratedShape.draw();
}
}
- 定义具体的边框装饰器
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("画边框!");
}
}
- 演示
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)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。它向现有的系统添加一个接口,来隐藏系统的复杂性。
这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
它的优点是可以减少系统相互依赖、提高灵活性、提高了安全性。但是它不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
举个例子:还是画各种图形的例子,比如要画圆形、矩形、三角形,没画一种图像都要拿到对应的抽象,并调用绘制方法,如果要画的形状过多,这么多的抽象就不好管理了,而如果使用外观设计模式,提供一个统一的抽象,在这个抽象中就可以完成上面不同的绘制,这样就方便了我们的管理。
下面使用程序演示下上面的例子:
- 定义形状的接口
public interface Shape {
void draw();
}
- 定义圆形的实例
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("开始画圆!");
}
}
- 定义矩形的实例
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("开始画矩形!");
}
}
- 定义三角形的实例
public class Triangle implements Shape {
@Override
public void draw() {
System.out.println("开始画三角形!");
}
}
- 定义一个外观类,并调用上面的功能
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();
}
}
- 演示
public class demo {
public static void main(String[] args) {
ShapeFacade shapeFacade = new ShapeFacade();
shapeFacade.drawCircle();
shapeFacade.drawRectangle();
shapeFacade.drawSquare();
}
}
外观设计模式还是比较容易理解的,就是把多个功能统一整个到一个对象中,由这个对象再去调用具体的类和方法。
四、代理设计模式
通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或调用后处理。既(AOP微实现) 。
代理有分静态代理和动态代理,静态代理就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。而动态代理是在我们使用时,动态的生成代理对象,他是在内存中构建代理对象的。
举个例子,在做数据库操作时,一般我们都会在事物中做SQL的操作,那就需要在操作前开启事物,操作后如果成功就需要提交事物,如果代用代理设计模式,就可以将事物开启提交逻辑放在代理类中,被代理的类,只需要关注业务逻辑即可。
我们以支付和事物为例演示下,代理模式
1. 采用静态代理,实现上面例子
- 定义支付接口
public interface PayInterFace {
void pay();
}
- 定义微信支付实现
public class WxPay implements PayInterFace {
@Override
public void pay() {
System.out.println("支付中...");
}
}
- 定义支付的代理类
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("提交事物!");
}
}
- 演示
public class demo {
public static void main(String[] args) {
PayInterFace pay = new PayProxy(new WxPay());
pay.pay();
}
}
上面的静态代理,可以看出,我们需要对每个被代理对象设计一个代理类,如果代理的功能非常多,那就需要开发人员写特别多的代理类,下面可以看下动态代理的使用。
2. 采用动态代理,实现上面例子
这里使用JDK自带的动态代理来实现
- 还是上面的例子,我们再定义一个支付宝的支付实现
public class ZfbPay implements PayInterFace {
@Override
public void pay() {
System.out.println("支付宝支付中...");
}
}
- 定义代理对象,采用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;
}
}
- 演示
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();
}
}
上面使用一个代理类,代理了多个对象,相对于静态代理,是代码更简介,灵活性也更高。
以上是关于设计模式-结构型模式讲解下(装饰者外观代理)的主要内容,如果未能解决你的问题,请参考以下文章