大家好,这里是每周陪你进步的网管~其实不是每周,是扬州上周~真的没什么进展继续...这周我们继续我们搁置了一段时间的设计模式系列。上次我们分享的是责任链模式。在文章的最后,我们提到了装饰者模式。两者虽然结构相似,但用途不同。装饰器模式本身就是代理模式的一种特殊应用,所以在这篇文章中,我们先学习代理模式的组成和用法,后面再学习装饰器。看过我文章的同学可能已经发现,虽然教材将设计模式分为构造型、结构型、行为型三大块,但我并没有按照这个大纲展开内容,而是更加注重连贯性点,尝试使一个模型有可能导致另一个相关模型。那么在学习了“流程开发三利器”——模板、策略和责任链三种行为模式之后,我们先放其他行为模式,先学习两种结构模式——代理和装饰器。什么是代理模式代理模式是一种结构化设计模式。代理控制对原始对象的访问,允许在请求提交给原始对象前后进行一些处理,从而增强了对原始对象的逻辑处理。上述代理一般称为代理对象或直接称为代理--Proxy。逻辑处理的原始对象通常称为服务对象。代理必须实现与服务对象相同的接口,以便客户端可以愚蠢地混淆自己。是使用代理还是真正的服务对象,让代理在客户端不知情的情况下增强服务对象的处理逻辑。处理逻辑的增强是什么?或者,换句话说,对核心功能进行增强?比如处理客户端查询用户订单信息的APIHandler就是核心处理逻辑。增强的逻辑是我们在查询订单信息前需要验证请求是否为有效用户,记录请求的参数和返回的响应数据等。.看完上面对代理模式的解释,你可能还是觉得有点笼统。让我们在下面编写一个简单的代码示例。在这个过程中,你几乎会发现:“咦,原来是代理模式,我用过~!”下面我们一起开始这个例子代理模式的使用演示假设有一个Car类型typeCarstruct{}代表一辆汽车,汽车的主要行为是能够被驾驶,所以Car需要实现一个接口(interface)代表驾驶行为的Vehicle,这个接口只有一个方法Drive()。"本文用到的完整可运行源码可以发到公众号「网管必唯」【设计模式】获取"typeVehicleinterface{Drive()}typeCarstruct{}func(c*Car)Drive(){fmt.Println("Carisbeingdriven")}Car的结构体指针通过实现Drive()方法来实现Vehicle接口。现在我们只需要实例化一个Car的实例,在该实例上调用Drive()方法就可以让汽车开车了,但是如果我们的司机还是未成年人,那么地球上绝大部分国家都是不允许开车的。如果司机开车有年龄限制,我们该怎么办?在Car结构中添加Age字段显然是不合理的,因为我们要表达的是司机的年龄,而不是汽车的年龄。同样的,我们也不应该在Car()方法实现的Drive中加入司机的年龄,这样会导致每个实现了Vehicle接口的类型在自己的Drive()方法中加入类似的判断。这时候通常的做法是添加一个代表驱动的类型Driver。输入Driverstruct{Ageint}然后是包装Driver和Vehicle类型的包装类型。》文中使用的完整可运行源码去公众号《网络管理口bi唯》发送【设计模式】接收"typeCarProxystruct{vehicleVehicledriver*Driver}funcNewCarProxy(driver*Driver)*CarProxy{return&CarProxy{&Car{},driver}}在这种情况下,我们可以传递它。当使用包装器类型来代理车辆属性的Drive()行为时,将驾驶添加到其中Driveragelimit。func(c*CarProxy)Drive(){ifc.driver.Age>=16{c.vehicle.Drive()}else{fmt.Println("Drivertooyoung!")}}这个编程相信大家都用过一般开发中的技术,这其实就是代理模式。现在我们已经通过代理模式将检查驱动程序的行为扩展到Car类型的Drive()行为。下面我们来执行程序试试效果。》本文用到的完整可运行源码可以发到公众号《网络管理备忘》【设计模式】获取"funcmain(){car??:=NewCarProxy(&Driver{12})car.Drive()//输出驱动太年轻了!car2:=NewCarProxy(&Driver{22})car2.Drive()//OutputCarisbeingdriven}执行后的结果表明,我们不需要为服务对象——Car类型添加任何属性和方法。而是我们只是把客户端的Drive()方法(英文叫delegate)的调用委托给它上面代理层的vehicle属性的Drive方法,并且在前面加上年龄校验的行为,这样就可以实现什么我们想要效果。看完例子,相信大家在写代码的时候就明白了如何使用代理模式了。接下来我们从代码中走出,把代理模式的整体结构描述的更清楚一些。根据上面开头的描述看到代理模式以及下面的代码示例,我们总结出参与代理模式的角色有四种:客户端、服务接口、服务类和代理类。它们之间的关系用一张UML类图表示如下:代理模式-UML类上面的UML类图中有四个角色,这四个角色在代理模式下的职责是分别的。服务接口(ServiceInterface)声明了服务类要实现的接口。服务类的业务处理逻辑在这里定义在接口方法中,代理类也必须遵循接口来伪装成一个服务对象。服务(Service)类,如上所述,提供了实际业务逻辑的原始对象。代理(Proxy)类包含一个服务对象作为成员变量。代理完成其任务(如惰性初始化、日志记录、访问控制和缓存等)后,会将请求传递给服务对象。通常,代理会管理其服务对象的整个生命周期,以增强服务对象,从而使与核心业务逻辑无关的增强逻辑可以由代理来实现。客户端(Client)通过统一的接口与服务或代理进行交互,所以服务对象的代理可以用在所有需要服务对象的代码中,客户端是完全不会感知的。在proxy模式下扩展proxy模式。通过让代理类实现与服务类相同的接口,将代理类伪装成服务类。当客户端请求代理时,代理将请求委托给它持有的真实服务类。我们可以在委托过程中添加增强逻辑。如果我们把代理类看成一个服务对象,然后给代理类添加代理,再给代理添加代理,那么就变成了另一种设计模式——装饰器模式。其实装饰者模式本身就是一种代理模式。对于特殊的应用,后面我们会学习装饰器的内容。
