从零开始单排学设计模式「装饰模式」黑铁 I
阅读本文大概需要 3.6 分钟。
本篇是设计模式系列的第四篇,虽然之前也写过相应的文章,但是因为种种原因后来断掉了,而且发现之前写的内容也很渣,不够系统。
所以现在打算重写,加上距离现在也有一段时间了,也算是自己的一个回顾吧!
学而时习之,不亦说乎。
推荐阅读:
目前段位:黑铁 I
Let's Go!
前言
设计模式不是语法,是一种巧妙的写法,能把程序变的更加灵活。架构模式比设计模式大,架构模式是战略,而设计模式是战术。
设计模式分为3大类型:创建型,行为型,结构型,总共有23种。
装饰模式
装饰模式(Decorator)指的是在不必改变类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
业务需求
公司接到一个任务,需要为某平台开发一个搭配不同服饰的小项目,比如类似QQ、网络游戏或论坛都有的Avatar系统(为了简化代码,直接使用控制台模拟)。
代码实现
经过公司的慎重讨论(实际就几秒钟),开发这一个项目的重任,又当仁不让的被产品经理交给了我,我:脸上笑嘻嘻,心里MMP。发一下下的小牢骚,不过还是抓紧干活。
思索一下,该系统要为不同的人进行装扮,所以定义一个人的类,不用每次装扮其他人时修改该类的代码。
然后人身上要有很多的服饰,比如:大T恤、垮裤、鞋子等等,然后穿上之后,需要展示出来。所以这里的话,可以抽象出一个服饰的基类,然后各个具体的服饰都继承该基类即可。
代码如下:
Person类
/**
* @author: LKP
* @date: 2019/2/16
*/
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public void show() {
System.out.println("装扮者:" + name);
}
}
服装抽象类
/**
* @author: LKP
* @date: 2019/2/16
*/
public class Finery extends Person {
protected Person component;
/**
* 打扮
* @param component
*/
public void decorate(Person component){
this.component = component;
}
@Override
public void show() {
if(null != component){
component.show();
}
}
}
具体服饰类
/**
* @author: LKP
* @date: 2019/2/16
*/
public class TShirts extends Finery {
@Override
public void show() {
System.out.println("大T恤");
}
}
class BigTrouser extends Finery {
@Override
public void show() {
System.out.println("垮裤");
}
}
class Sneakers extends Finery{
@Override
public void show() {
System.out.println("破球鞋");
}
}
class LeatherShoes extends Finery{
@Override
public void show() {
System.out.println("皮鞋");
}
}
class Tie extends Finery{
@Override
public void show() {
System.out.println("领带");
}
}
class Suit extends Finery{
@Override
public void show() {
System.out.println("西装");
}
}
这里内部类,只是为了较少代码量,实际开发中可不要偷懒,按实际来创建。
客户端代码
/**
* @author: LKP
* @date: 2019/2/16
*/
public class Main {
public static void main(String[] args) {
Person person = new Person("孤独键客");
System.out.println("第一种装扮:");
Finery tShirts = new TShirts();
Finery bigTrouser = new BigTrouser();
Finery sneakers = new Sneakers();
tShirts.show();
bigTrouser.show();
sneakers.show();
person.show();
System.out.println("\n第二种装扮:");
Finery suit = new Suit();
Finery tie = new Tie();
Finery leatherShoes = new LeatherShoes();
suit.show();
tie.show();
leatherShoes.show();
person.show();
}
}
代码简单搞定,接下来来看一下运行结果
搞定收工,审视一下,自我感觉还算不错,如果新装扮只需改变一下调用顺序即可,如果又新人物,只需重新new一个Person类就可以了。
接下里将项目提交上传,然后告诉leader一声,over,离下班时间还早,好像还可以做点其他的事情~。
正当你准备打开去干点其他事情,leader回复你了:
leader:“你仔细看看这段代码,这样写意味着什么?
你想象一下,是不是把‘大T恤’、‘垮裤’、‘破球鞋’、‘装扮者’一个一个词显示出来,是不是相当于你光着身子,一个一个把这些穿上,这可有点像脱衣舞哦~”。
我:“你意思是,这些应该都在内部组装完毕,然后在显示出来?”。
leader:"宾果,而且还要按照正确的顺序串联起来控制,这里有点难度,修改好之后再给我"。
这似乎和某种设计模式有关,难道是建造者模式吗?不对,建造者模式要求建造的过程必须是稳定的,而这个穿搭的过程是不固定的,一个有个性的人又无数种方案。
经过一番查找,这恰恰最适合用装饰模式了。
我们修改一下具体的服饰类
/**
* @author: LKP
* @date: 2019/2/16
*/
public class TShirts extends Finery {
@Override
public void show() {
System.out.println("大T恤");
super.show();
}
}
class BigTrouser extends Finery {
@Override
public void show() {
System.out.println("垮裤");
super.show();
}
}
class Sneakers extends Finery{
@Override
public void show() {
System.out.println("破球鞋");
super.show();
}
}
class LeatherShoes extends Finery{
@Override
public void show() {
System.out.println("皮鞋");
super.show();
}
}
class Tie extends Finery{
@Override
public void show() {
System.out.println("领带");
super.show();
}
}
class Suit extends Finery{
@Override
public void show() {
System.out.println("西装");
super.show();
}
}
再修改一下客户端代码:
/**
* @author: LKP
* @date: 2019/2/16
*/
public class Main {
public static void main(String[] args) {
Person person = new Person("孤独键客");
System.out.println("第一种装扮:");
Sneakers sneakers = new Sneakers();
BigTrouser bigTrouser = new BigTrouser();
TShirts tShirts = new TShirts();
sneakers.decorate(person);
bigTrouser.decorate(sneakers);
tShirts.decorate(bigTrouser);
tShirts.show();
System.out.println("第二种装扮:");
LeatherShoes leatherShoes = new LeatherShoes();
Tie tie = new Tie();
Suit suit = new Suit();
leatherShoes.decorate(person);
tie.decorate(leatherShoes);
suit.decorate(tie);
suit.show();
}
}
第二版的程序写完了,来测试一下
完美搞定,哈哈,我还可以换种装饰方式
看下结果
光着膀子、打着领带、下身垮裤、脚上皮鞋,绝对的极具个性。
最后,完美搞定,提交代码~~~
装饰模式UML类图
总结
来总结一下装饰模式:
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
如何解决:将具体功能职责划分,同时继承装饰者模式。
关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。
应用实例: 1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。 2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。
使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。
注意事项:可代替继承。
往期精彩回顾
我被程序员坑了600万致公司倒闭,当事人逐条反驳:这锅我不背
欢迎关注我的公众号「程序员的成长之路」,阅读更多精彩!
从零开始单排学设计模式「装饰模式」黑铁 I的更多相关文章
- 从零开始单排学设计模式「策略模式」黑铁 II
阅读本文大概需要 1.7 分钟. 本篇是设计模式系列的第三篇,虽然之前也写过相应的文章,但是因为种种原因后来断掉了,而且发现之前写的内容也很渣,不够系统.所以现在打算重写,加上距离现在也有一段时间了, ...
- 从零开始单排学设计模式「简单工厂设计模式」黑铁 III
阅读本文大概需要 2 分钟. 本篇是设计模式系列的第二篇,虽然之前也写过相应的文章,但是因为种种原因后来断掉了,而且发现之前写的内容也很渣,不够系统.所以现在打算重写,加上距离现在也有一段时间了,也算 ...
- 从零开始单排学设计模式「UML类图」定级赛
阅读本文大概需要 3.5 分钟. 本篇是设计模式系列的开篇,虽然之前也写过相应的文章,但是因为种种原因后来断掉了,而且发现之前写的内容也很渣,不够系统. 所以现在打算重写,加上距离现在也有一段时间了, ...
- 一个「学渣」从零开始的Web前端自学之路
从 13 年专科毕业开始,一路跌跌撞撞走了很多弯路,做过餐厅服务员,进过工厂干过流水线,做过客服,干过电话销售可以说经历相当的“丰富”. 最后的机缘巧合下,走上了前端开发之路,作为一个非计算机专业且低 ...
- 「补课」进行时:设计模式(5)——从 LOL 中学习代理模式
1. 前文汇总 「补课」进行时:设计模式系列 2. 从 LOL 中学习代理模式 我是一个很喜欢玩游戏的人,虽然平时玩游戏的时间并不多,但我也是一个忠实的 LOL 的爱好者,就是段位有点惨不忍睹,常年倔 ...
- 零元学Expression Design 4 - Chapter 7 使用内建功能「Clone」来达成Path的影分身之术
原文:零元学Expression Design 4 - Chapter 7 使用内建功能「Clone」来达成Path的影分身之术 本章所介绍的是便利且快速的内建工具Clone ? 本章所介绍的是便利且 ...
- 零元学Expression Blend 4 - Chapter 34 啊~!!我不要毛毛的感觉!-使用布局修整「UseLayoutRounding」
原文:零元学Expression Blend 4 - Chapter 34 啊~!!我不要毛毛的感觉!-使用布局修整「UseLayoutRounding」 本章将介绍UseLayoutRounding ...
- 零元学Expression Blend 4 - Chapter 18 用实例了解互动控制项「CheckBox」II
原文:零元学Expression Blend 4 - Chapter 18 用实例了解互动控制项「CheckBox」II 延续上一章的CheckBox教学,本章将以实作继续延伸更灵活的运用CheckB ...
- 零元学Expression Blend 4 - Chapter 17 用实例了解互动控制项「CheckBox」I
原文:零元学Expression Blend 4 - Chapter 17 用实例了解互动控制项「CheckBox」I 本章将教大家如何运用CheckBox做实作上的变化:教你如何把CheckBox变 ...
随机推荐
- windows 环境下 dbnamodb 环境搭建与使用
https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/installing.html 安装 AWS Command Line Interface ...
- springmvc 配置异步请求
最开始按照网上配置了一个servlet class 没有继承Filter .结果报错.网上有文章说是tomcat 启动加载的servlet-3.0- api 加载了 tomcat 安装目录下lib里边 ...
- 201771010134杨其菊《面向对象程序设计(java)》第十六周学习总结
第十六周学习总结 第一部分:理论知识 1. 程序是一段静态的代码,它是应用程序执行的蓝本.进程是程序的一次动态执行,它对应了从代码加载.执行至执行完毕的一个完整过程.操作系统为每个进程分配一段独立的内 ...
- “天龙八步”细说浏览器输入URL后发生了什么
本文摘要: 1.DNS域名解析: 2.建立TCP连接: 3.发送HTTP请求: 4.服务器处理请求: 5.返回响应结果: 6.关闭TCP连接: 7.浏览器解析HTML: 8.浏览器布局渲染: 总结 输 ...
- jquery datatables+MVC+WCF
view @{ Layout = null;} <!DOCTYPE html><html><head> <title>111</title> ...
- mysql 报错 Packets larger than max_allowed_packet are not allowed
登录 mysql, 执行命令 : show variables like '%max_allowed_packet%' 重新设置: set global max_allowed_packet = 1 ...
- Spring-MVC运行原理
一. Spring-MVC的对象初始化,即 bean放入context的beanFactory中. 1. 对象的初始化工作主要在org.springframework.web.servlet.Fram ...
- iOS 关于重定向的那些事(NSURLProcotol-WKWebView)
重定向定义:重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向.域名的重定向.路由选择的变化也是对数据报文经由路径的一种重定向). NSURLProt ...
- OO第9-11作业总结
一. 规格化设计 规格化抽象,即将执行的细节抽象为用户所需求的行为(模块做什么). 主要作用在于提高工程设计中的可维护性,可读性,明确功能,使整个编程任务变得清晰有序以减少程序BUG. 说其发展历 ...
- Java在ServletContextListener、过滤器、拦截器解决对象无法注入问题
1.通用方法: // 数据库日志操作对象 private LogInfoServiceIFC logInfoServiceProxy; @Override public void contextIni ...