java经典设计模式4,JAVA设计模式(4) 之装饰设计模式

在现实生活中我们的汽车都具备跑的功能,我们可以不改变汽车原有功能的前提下,把它放入一个装修厂,开进去让里面给咱们的车子做一些装饰,开出来之后呢,就具备了上天的功能了(技术可达是可以的哈),这就给原来的汽车对象,增加了额外的功能。

再举一个例子:假设我们非常爱惜一张照片,我们可以不改变照片本身前提下,给它增加一个相框,使得它具有防潮的功能,而且用户可以根据需要给它增加不同类型的相框,甚至可以在一个小相框的外面再套一个大相框。这就是针对照片这个对象的装饰,在软件工程中,同样存在类似的功能,使用装饰模式可以透明的增加指定对象的功能。

1、装饰模式的引入

首先咱们来看一段代码:

假设我要设计一个汽车类,然后在里面定义了汽车可能存在的功能(后面我还要扩展汽车的功能):

public class Car {

public void run(){

System.out.println("能跑");

}

public void fly(){

System.out.println("能飞");

}

public void sweep(){

System.out.println("能游");

}

public void show(){

System.out.println("该汽车拥有的功能:");

this.run();

this.fly();

this.sweep();

}

}

public class Main {

public static void main(String[] args) {

Car bus = new Car();

bus.show();

}

}

这段代码并没有什么设计可言的。运行结果就不贴出来了,可见,我们在客户端造了一个巴士,调用了巴士的 show 方法后,发现有一些功能并不是巴士的(飞、游泳),这样显然是存在问题的。那么我们可能会作如下修改:

使用继承,每个继承体系归类。

//接口可以改为抽象类

public interface Car {

//只要是有汽车,都具备跑的功能

void run();

//调用展示该汽车存在的功能

void show();

}

public class RunCar implements Car{

//普通汽车只具备跑的功能

public void run() {

System.out.println("可以跑");

}

public void show() {

this.run();

}

}

public class FlyCar implements Car {//扩展的汽车具备飞的功能

@Override

public void run() {

System.out.println("可以跑");

}

// 定义自己的功能

public void fly() {

System.out.println("可以飞");

}

@Override

public void show() {

this.run();

this.fly();

}

}

public class SwimCar implements Car{//扩展的汽车具备游泳的功能

@Override

public void run() {

System.out.println("可以跑");

}

public void swim(){

System.out.println("可以游泳");

}

@Override

public void show() {

this.run();

this.swim();

}

}

然后在客户端调用:

public class Main {

public static void main(String[] args) {

Car bus = new RunCar();

bus.show();

Car flyCar = new FlyCar();

flyCar.show();

}

}

运行结果如下:

ab9d20c23869226e15ad7174d6662d44.png

我们这里使用继承的方式来扩展系统(Car)的功能,这样拥有了设计可言,但是还是存在问题的。问题在于如果增加子类,他拥有“遁地”的功能的话(当然技术先进可以做到哈,不要在意这些细节),仍然要在遁地这个子类里面定义额外的“遁地”方法。这个时候,为了解决这种继承扩展功能问题,就引入了本节的内容——装饰模式。装饰模式是扩展系统功能的最佳选择。装饰模式是对已有对象的功能进行扩展(装修、装饰),以获得更加符合用户需求的对象,使得对象具有更加强大的功能。

2、装饰模式概述

装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为,在现实生活中,这种情况也到处存在,例如装修窗户,我们可以不改变窗户本身,给它增加一些额外的装饰(比如窗花),增加他的可观赏性,而且用户可以根据需要给它增加不同类型的窗花,甚至可以装饰多层。

装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。在装饰模式中引入了装饰类,在装饰类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩充原有类的功能。

装饰模式定义如下:

动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。

在装饰模式中,为了让系统具有更好的灵活性和可扩展性,我们通常会定义一个抽象装饰类,而将具体的装饰类作为它的子类,装饰模式结构如图所示:

82c07b801f1a6a93e6888c1f65326caf.png

在装饰模式结构图中包含如下几个角色:

Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。【上述 Car 就是这个角色】

ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。【上述 RunCar 就是这个角色】

Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。比如针对开头的案例,它可以对 Car 增加除了跑额外的功能 “可以游泳”、“下水”、“遁地”等。

ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。【上述 FlyCar 和 SwinCar 可以作为整个角色对 Car 动能进行扩展】

由于具体构件类和装饰类都实现了相同的抽象构件接口,因此装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。

装饰模式的核心在于抽象装饰类的设计,其典型代码如下所示:

class Decorator implements Component{

//持有抽象构件的引用

private Component component;

//注入一个抽象构件类型的对象(依赖倒置)

public Decorator(Component component) {

this.component=component;

}

public void operation(){

//调用原有业务方法

component.operation();

}

}

在抽象装饰类 Decorator 中定义了一个 Component 类型的对象 component,维持一个对抽象构件对象的引用,并可以通过构造方法或 Setter 方法将一个 Component 类型的对象注入进来,同时由于 Decorator 类实现了抽象构件 Component 接口,因此需要实现在其中声明的业务方法 operation(),需要注意的是在 Decorator 中并未真正实现 operation() 方法,而只是调用原有 component 对象的 operation() 方法,它没有真正实施装饰,而是提供一个统一的接口,将具体装饰过程交给子类完成。

在 Decorator 的子类即具体装饰类中将继承 operation() 方法并根据需要进行扩展,典型的具体装饰类代码如下:

class ConcreteDecorator extends Decorator{

public ConcreteDecorator(Component component){

super(component);

}

public void operation(){

super.operation(); //调用原有业务方法

addedBehavior(); //调用新增业务方法

}

//新增业务方法

public void addedBehavior(){

……

}

}

在具体装饰类中可以调用到抽象装饰类的 operation() 方法,同时可以定义新的业务方法,如 addedBehavior()。

由于在抽象装饰类 Decorator 中注入的是 Component 类型的对象,因此我们可以将一个具体构件对象注入其中,再通过具体装饰类来进行装饰;此外,我们还可以将一个已经装饰过的 Decorator 子类的对象再注入其中进行多次装饰,从而对原有功能的多次扩展。

3、装饰模式实战

针对文章开头处的案例,使用装饰设计模式进行修改。

对于装饰模式,可以难于理解的地方在于 Decorator 抽象装饰类为何会继承或者实现 Component 抽象构建类。如果我们不继承 Component 构建类使用装饰模式的时候,代码如下:

UML图:

7c06c077da7d6ce803b1aa3c7bda55da.png

代码:

```java

//Component抽象构件角色

public interface Car {

//只要是有汽车,都具备跑的功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382985.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java读取gxk文件,Java中常见的IO流及其使用

Java中IO流分成两大类,一种是输入流,所有的输入流都直接或间接继承自InputStream抽象类,输入流作为数据的来源,我们可以通过输入流的read方法读取字节数据;另一种是输出流,所有的输出流都直接或间接继承自O…

matlab+voronoin函数,在Voronoi区域中生成随机点,并创建具有高维数据的Voronoi区域...

我正在使用k-means聚类算法,并且对于每个聚类质心,我试图为质心生成n维Voronoi区域 . 之后我需要从Voronoi区域生成随机点 .我已经尝试使用Matlab / Octave和scipy来获得n维Voronoi区域 . 但我有两个问题 .生成顶点和区域后,如何从区域生成随…

matlab双纵轴刻度覆盖问题,求助: matlab双纵轴换图问题

非常感谢!不过,y2的范围是-1*(10^6),7*(10^6),但是不等分:(把y1的范围调成0.4:0.2:5.8也有28个元素,然后y2也有28个元素,但是不等分,是个曲线,而且,这个曲线的值与y1是有关的。数据见附件syms d…

php最新图片漏洞,2018最新PHP漏洞利用技巧

本文学习了几种新式的php exploit方法,在此做一笔记文件删除漏洞, unlink()Phar 反序列化, file*()PHP对象实例化, ReflectionClass()0x01 WordPress Design Flaw Leads to WooCommerce RCEWooCommerce 3.4.6本版本之前存在任意删除漏洞,因为WordPress的…

php v-for=,Vue中v-for循环节点的实现代码

本篇文章给大家带来的内容是关于Vue中v-for循环节点的实现代码,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。Title父循环第一次子循环第一次json数据的第几条数值{{index}}{{indo}}{{bp.index}}{{bp.childName}}let ernew …

matlab寻找向量最小值,matlab – 在排序向量中快速搜索大于x的最小值

由于输入已经排序,自定义二进制搜索应该有效(您可能需要对边缘情况进行一些更新,即请求的值小于数组的所有元素):function [result, res2] binarySearchExample(val)%// Generate example data and sort itN 100000000;a rand(N, 1);a sort(a);%// Run the algo…

搜matlab代码的网站,LTE小区搜索matlab仿真

【实例简介】LTE小区搜索过程的matlab仿真,比较详细,内容不错【实例截图】【核心代码】35738649matlab└── matlab├── Bc.m├── CellSearch.m├── PSS_detection_correction.m├── Tc.m├── absx2.m├── add_header_to_bin.m├── add_h…

php过气了吗,留几手 留几手过气原因

1、很多时候,人们做事情只是为了自己,没有任何理由,没有任何结果,只是为了满足一些内心的期望。2、太理智的人,往往爱到一半,本能地退却。唯一突出的是他的JB。3、怎样才能自由地睡去女文艺青年&#xff1f…

live2d PHP,Live2dHistoire_setting.php

if(!defined(EMLOG_ROOT)) {exit(error!);}function plugin_setting_view(){$live2d_setunserialize(ltrim(file_get_contents(dirname(__FILE__)./live2d.com.php),<?php die; ?>));?>KEY&#xff1a;音乐1&#xff1a;音乐2&#xff1a;音乐3&#xff1a;音乐4&a…

mysql 远程load data,PyMySQL将(文件)数据加载到远程MySQL实例时发生错误/异常

我正在使用PyMySQL-0.5.0并在将数据从文件加载到远程MySQL实例时遇到了一个模糊的错误/异常。在执行“loaddatalocalinfile…”语句时&#xff0c;我看到一个异常&#xff0c;它说&#xff1a;The used command is not allowed with this MySQL version。在如果PyMySQL支持此操…

matlab频率阻抗,有分析阻抗的matlab脚本吗?

以上来自于谷歌翻译以下为原文Interesting...- You cross-posted to two forums. I have deleted the other post.- You dont indicate what scope you are using or what you have tried.Most Keysight (and Agilent) scopes have an FFT or Spectrum function available. Hav…

php中修改弹窗的样式,CSS变形弹窗效果示例

大家都知道&#xff0c;弹出窗体已经是现在网页常用的一种交互设计&#xff0c;在这个注重交互动画体验的时代&#xff0c;网页弹窗也是可以来点新鲜点子的&#xff0c;比如今天分享的CSS 变形Modal Window。当用户点击按钮时&#xff0c;按钮将会变成一个全屏的屏幕&#xff0…

php 开发高德地图地理围栏,高德地图-地理围栏功能实现

最近需要实现一个地理围栏相关的功能。项目是和骑行相关的&#xff0c;主要是当游客或者骑友定位地址进入到对应的景点的地理围栏里面&#xff0c;则播报景点相关的报道语音。接到需求之后&#xff0c;我开始查看高德的相关API&#xff0c;由于围栏是多边形的&#xff0c;则需要…

java abstractrequest,Java AbstractJackson2HttpMessageConverter類代碼示例

import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter; //導入依賴的package包/類Testpublic void testDefaultConfig() throws Exception {loadBeanDefinitions("mvc-config.xml", 14);RequestMappingHandlerMapping mapping app…

golang调用matlab,Golang中Proto编写和生成

test.proto文件syntax "proto3";//指定proto文件版本package go; //指定文件缩放的package名//定义对象message Test {enum PhoneType //枚举消息类型{MOBILE 0; //proto3版本中&#xff0c;首成员必须为0&#xff0c;成员不应有相同的值HOME 1;WORK 2;}int32 fl…

php折半查找面试题,php 面试题(一)

最近转载一些面试题&#xff0c;希望能给找工作的朋友们带来一点帮助。1.写出5个以上你所知道的常用的Linux命令和它的功能cat&#xff0c;显示文件内容。cd&#xff0c;改变目录路径。cp&#xff0c;复制文件。find&#xff0c;查找文件。grep&#xff0c;搜索、过滤信息。ls&…

次梯度法matlab代码,实例:连续化次梯度法解 LASSO 问题

实例&#xff1a;连续化次梯度法解 LASSO 问题我们将在此页面中构造一个 LASSO 问题并且展示连续化次梯度方法在其中的应用。目录构造LASSO优化问题设定随机种子。clear;seed 97006855;ss RandStream(mt19937ar,Seed,seed);RandStream.setGlobalStream(ss);构造 LASSO 优化问…

php变量使用,php变量的使用

来源:www.cncfan.com | 2006-1-11 | (有1856人读过)就像大部份的结构化程序&#xff0c;有所谓的全局变量与局部变量&#xff0c;PHP 在这方面也是有相似之处。在 PHP 的程序执行时&#xff0c;系统会在内存中保留一块全局变量的区域。实际运用时&#xff0c;可以透过 $GLOBALS…

php syncml 协议,基于改进的SyncML协议的图像安全同步技术研究

Image secure synchronization technology research based on improved SyncML protocolJIA Zhaolong1贾兆拢(1991-)&#xff0c;女&#xff0c;北京邮电大学硕士生&#xff0c;主要研究方向&#xff1a;网络安全技术与应用MA Zhaofeng2马兆丰(1974-)&#xff0c;男&#xff0c…

php 文字水印如何居中,php文字水印和php图片水印实现代码(二种加水印方法)

$dst_path dst.jpg;$src_path src.jpg;//创建图片的实例$dst imagecreatefromstring(file_get_contents($dst_path));$src imagecreatefromstring(file_get_contents($src_path));//获取水印图片的宽高list($src_w, $src_h) getimagesize($src_path);//将水印图片复制到目…