设计模式(十二)Decorator模式
Decorator模式就是不断地为对象添加装饰的设计模式。以蛋糕为例,程序中的对象就相当于蛋糕,然后像不断地装饰蛋糕一样地不断地对其增加功能,它就变成了使用目的更加明确的对象。
首先看示例程序的类图。

然后看示例程序代码。
package bigjunoba.bjtu.decorator;
public abstract class Display {
public abstract int getColumns();
public abstract int getRows();
public abstract String getRowText(int row);
public final void show() {
for (int i = 0; i < getRows(); i++) {
System.out.println(getRowText(i));
}
}
}
Display类是可以显示多行字符串的抽象类。getColumns方法用来获取横向行数,getRows方法用来获取纵向行数,getRowText方法用于获取指定的某一行的字符串,show方法是用来显示所有行字符串,首先获得行数,然后循环打印每一行的字符串。
package bigjunoba.bjtu.decorator;
public class StringDisplay extends Display{
private String string;
public StringDisplay(String string) {
this.string = string;
}
@Override
public int getColumns() {
return string.getBytes().length;
}
@Override
public int getRows() {
return 1;
}
@Override
public String getRowText(int row) {
if (row == 0) {
return string;
} else {
return null;
}
}
}
StringDisplay类用于显示单行字符串。string字段中保存的是要显示的字符串,由于StringDisplay类显示的是单行字符串,因此getColumns方法就是返回字符串的长度,而getRows方法返回的行数就是1,由于返回的是单行字符串,所以getRowText方法只有在传入的参数是0时才会返回字符串。StringDisplay类就相当于生日蛋糕中的核心蛋糕。
package bigjunoba.bjtu.decorator;
public abstract class Border extends Display {
protected Display display;
protected Border(Display display) {
this.display = display;
}
}
Border类继承了Display类,但它是装饰边框的抽象类。这里有一些疑惑。装饰边框与装饰物具有了相同的方法,因此也就具有了一致性。
还需要注意的是,Border类中的display字段,表示的是被装饰物,也就是说,只要是display类的子类,都可以传递进来保存在display字段中。更有趣的是,当然可以把Border类的子类传递进来,这样Border类的子类表示的装饰边框类中又有一个display字段,又可以传递进去一个边框或装饰物,反复循环。可以理解为实现了不断增加新的装饰物。
package bigjunoba.bjtu.decorator;
public class SideBorder extends Border {
private char borderChar;
protected SideBorder(Display display, char ch) {
super(display);
this.borderChar = ch;
// TODO Auto-generated constructor stub
}
@Override
public int getColumns() {
return 1 + display.getColumns();
}
@Override
public int getRows() {
return display.getRows();
}
@Override
public String getRowText(int row) {
return borderChar + display.getRowText(row) + borderChar;
}
}
SideBorder类可以用指定的字符来装饰字符串的左右两侧。borderChar字段用来保存指定的字符。首先通过调用父类的构造器指定display和ch。然后通过调用被装饰物display的相关方法来实现这一装饰目的。
package bigjunoba.bjtu.decorator;
public class FullBorder extends Border{
protected FullBorder(Display display) {
super(display);
}
@Override
public int getColumns() {
return 1 + display.getColumns() + 1;
}
@Override
public int getRows() {
return 1 + display.getRows() + 1;
}
@Override
public String getRowText(int row) {
if (row ==0) {
return "[" + makeLine('@', display.getColumns()) + "]";
} else if (row == display.getRows() + 1) {
return "[" + makeLine('@', display.getColumns()) + "]";
} else {
return "|" + display.getRowText(row - 1) + "|";
}
}
private String makeLine(char ch, int count) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < count + 1; i++) {
stringBuffer.append(ch);
}
return stringBuffer.toString();
}
}
FullBorder类在字符串的上下左右都加上装饰边框。这里需要理解一下这些方法。getColumns方法获得的列数,也就是字符数为被装饰物的字符数加上两侧边框字符数。getRows方法获得的行数是被装饰物的行数加上上下边框的行数
makeLine方法是连续地显示count次指定的字符ch,声明为private是因为防止被FullBorder以外的类使用。getRowText用于生成指定那一行的字符串,例如,row ==0表示下边框,row == display.getRows() + 1表示上边框。
package bigjunoba.bjtu.decorator;
public class Main {
public static void main(String[] args) {
Display display1 = new StringDisplay("Lianjiang");
Display display2 = new SideBorder(display1, '*');
Display display3 = new FullBorder(display2);
Display display4 =
new SideBorder(
new FullBorder(
new FullBorder(
new SideBorder(
new FullBorder(new StringDisplay("Lianjiang")),'*'
)
)
),'!'
);
System.out.println("这是display1的输出:");
display1.show();
System.out.println();
System.out.println("这是display2的输出:");
display2.show();
System.out.println();
System.out.println("这是display3的输出:");
display3.show();
System.out.println();
System.out.println("这是display4的输出:");
display4.show();
}
}
这是测试类。这里就不做过多解释了。
这是display1的输出:
Lianjiang 这是display2的输出:
*Lianjiang* 这是display3的输出:
[@@@@@@@@@@@]
|*Lianjiang*|
[@@@@@@@@@@@] 这是display4的输出:
![@@@@@@@@@@@@@@@]!
!|[@@@@@@@@@@@@@]|!
!||*[@@@@@@@@@]*||!
!||*|Lianjiang|*||!
!||*[@@@@@@@@@]*||!
!|[@@@@@@@@@@@@@]|!
![@@@@@@@@@@@@@@@]!
测试结果如图所示。结合测试类来分析,1的装饰边框是2,然后得到完全体后2的装饰框是3,最后4是组合装饰,也就是多重边框。
下面是Decorator模式的类图。

Component:增加功能的核心角色。也就是装饰前的蛋糕,只是定义了蛋糕的接口,在示例中,是Display类。
ConcreteComponent:实现了Component定义的接口的具体蛋糕。
Decorator:具有与Component相同的接口,内部保存了被装饰对象--Component,示例中也就是Border类。
ConcreteDecorator:具体的实现类。示例程序中的SideBorder类和FullBorder类。
这里要扩展的知识是继承和委托。
1.继承
继承可以让子类和父类具有一致性。举一个例子,父类Parent和子类Child,有这么一个情况就是,Child类的实例可以保存在Parent类型的变量中,也可以调用从Parent类中继承的方法。比如:
Parent obj = new Child();
obj.parentMethod();
也就是说,可以像操作Parent类的实例一样操作Child类的实例,这是将子类当做父类的一个例子。
反过来,如果想将父类当做子类看待,需要先进行类型转换。
Perent obj = new Child();
((Child)obj).child.Method();
2.委托
使用委托让接口具有透明性,自己和委托对象具有一致性。
先看一个例子:
abstract class Flower{
abstract void method();
}
class Rose extends Flower {
Violet obj = ...
void method(){
obj.method();
}
}
class Violet extends Flower(
void method(){
...
}
}
第一个例子是编写一个共同的抽象类Flower。
interface class Flower{
abstract void method();
}
class Rose implements Flower {
Violet obj = ...
void method(){
obj.method();
}
}
class Violet implements Flower(
void method(){
...
}
}
第二个例子就是编写一个Flower接口。
这两个例子主要是说明,Rose和Violet都有相同的method方法,但是Rose将method方法的处理委托给了Vidlet,这样就体现了method方法是共通的。
设计模式(十二)Decorator模式的更多相关文章
- 设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型)
设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决,不能解决就 ...
- 设计模式 ( 十二 ) 职责链模式(Chain of Responsibility)(对象行为)
设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决.不能解决就 ...
- 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)
设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的 ...
- 【转】设计模式 ( 十八 ) 策略模式Strategy(对象行为型)
设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成 ...
- 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)
设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...
- 设计模式 ( 十九 ) 模板方法模式Template method(类行为型)
设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行 ...
- C#设计模式之二十二访问者模式(Visitor Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第九个模式,该模式是[访问者模式],英文名称是:Visitor Pattern.如果按老规矩,先从名称上来看看这个模式,我根本不能获 ...
- C#设计模式之二十二备忘录模式(Memeto Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第十个模式,该模式是[备忘录模式],英文名称是:Memento Pattern.按老规矩,先从名称上来看看这个模式,个人的最初理解就 ...
- C#设计模式之二十二备忘录模式(Memento Pattern)【行为型】
一.引言 今天我们开始讲“行为型”设计模式的第十个模式,该模式是[备忘录模式],英文名称是:Memento Pattern.按老规矩,先从名称上来看看这个模式,个人的最初理解就是对某个对象的状态进行保 ...
- Java进阶篇设计模式之二 ----- 工厂模式
前言 在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模 ...
随机推荐
- Java 基础篇之编程基础
基本数据类型 java 是强类型语言,在 java 中存储的数据都是有类型的,而且必须在编译时就确定其类型. 基本数据类型变量存储的是数据本身,而引用类型变量存的是数据的空间地址. 基本类型转换 自动 ...
- ThinkPHP框架快速开发网站
使用ThinkPHP框架快速搭建网站 这一周一直忙于做实验室的网站,基本功能算是完成了.比较有收获的是大概了解了ThinkPHP框架.写一些东西留作纪念吧.如果对于同样是Web方面新手的你有一丝丝帮助 ...
- 常用Form表单正则表达式
前端常用form表单提交,校验正则表达式奉上!/** * 邮箱 * @param {*} s */ export function isEmail (s) { return /^([a-zA-Z0-9 ...
- 手动模拟JDK动态代理
为哪些方法代理? 实现自己动态代理,首先需要关注的点就是,代理对象需要为哪些方法代理? 原生JDK的动态代理的实现是往上抽象出一层接口,让目标对象和代理对象都实现这个接口,怎么把接口的信息告诉jdk原 ...
- UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 357: illegal multibyte sequence 错误解决方法(已解决)
今天在搭建数据驱动测试框架的时候遇到这个错误: 好在我英语水平还不错(也就六级水平吧),根据英文提示说是多字节数据顺序是非法的 顺着错误往上找发现 File "C:\Users\Mr雷的电脑 ...
- Mariadb 基于Mycat实现读写分离
环境:Mariadb主:192.168.200.129 Mariadb从:192.168.200.114 Mycat :192.168.200.112 (1) 安装jdk,先查看本机是 ...
- A-04 坐标轴下降法
目录 坐标轴下降法 一.坐标轴下降法流程 二.坐标轴下降法和梯度下降法的异同 更新.更全的<机器学习>的更新网站,更有python.go.数据结构与算法.爬虫.人工智能教学等着你:http ...
- ACM-图论-同余最短路
https://www.cnblogs.com/31415926535x/p/11692422.html 一种没见过的处理模型,,记录一下,,主要是用来处理一个多元一次方程的解的数量的问题,,数据量小 ...
- 最强最全的Java后端知识体系
目录 最全的Java后端知识体系 Java基础 算法和数据结构 Spring相关 数据库相关 方法论 工具清单 文档 @(最强最全的Java后端知识体系) 最全的Java后端知识体系 最全的Java后 ...
- 禅道部署(基于Linux)
部署步骤: 1. 查看Linux服务器是32位还是64位的 #getconf LONG_BIT 2. 禅道开源版安装包下载 下载站点1:#wget http://sourceforge.net/ ...