装饰模式(Decorator)
简介通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。
模式定义
在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。
优缺点
优点
- 采用装饰模式扩展对象的功能比采用继承方式更加灵活
- 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合
缺点
- 装饰模式增加了许多子类,如果过度使用会使程序变得很复杂
适用场景
- 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时
- 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰模式却很好实现
- 当对象的功能要求可以动态地添加,也可以再动态地撤销时
模型结构
- 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象;
- 具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责;
- 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能;
- 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任;
模型实现
package com.company.decorator;
public class DecoratorPattern {
public static void main(String[] args) {
Component zs = new Person("张三");
System.out.println("===================只装饰衣服===================");
Decorator clothesDecorator = new ClothesDecorator(zs);
clothesDecorator.show();
System.out.println("===================装饰衣服的基础上再装饰裤子===================");
Decorator trousersDecorator = new TrousersDecorator(clothesDecorator);
trousersDecorator.show();
}
}
//构件接口
interface Component {
void show();//构件方法
}
//具体构件角色==>人
class Person implements Component {
private final String name;
public Person(String name) {
this.name = name;
}
@Override
public void show() {
System.out.println(this.name + " 的装饰");
}
}
//抽象装饰器
abstract class Decorator implements Component {
private final Component component;
//装饰器构造方法,传入构件角色
public Decorator(Component component) {
this.component = component;
}
public void show() {
if (this.component != null) {
this.component.show();
}
}
}
//具体装饰器===》衣服
class ClothesDecorator extends Decorator {
public ClothesDecorator(Component component) {
super(component);
}
public void show() {
super.show();
System.out.println("装饰===》衣服");
}
}
//具体装饰器===》裤子
class TrousersDecorator extends Decorator {
public TrousersDecorator(Component component) {
super(component);
}
public void show() {
super.show();
System.out.println("装饰===》裤子");
}
}
运行结果:
===================只装饰衣服===================
张三 的装饰
装饰===》衣服
===================装饰衣服的基础上再装饰裤子===================
张三 的装饰
装饰===》衣服
装饰===》裤子
如果在使用Gin框架编写web应用程序中,如果里面包含了模板文件和静态文件,我们如何进行打包呢?本文主要记录该操作。
CFSSL是CloudFlare开源的一款PKI/TLS工具。 CFSSL 包含一个命令行工具 和一个用于 签名,验证并且捆绑TLS证书的 HTTP API 服务。 使用Go语言编写。
dd命令具有复制文件、转换文件和格式化文本的功能。但是这个命令的使用也要谨慎。这里不做过多说明,就是提示在使用的时候一定要注意。错误的操作可能会对系统造成不能挽回的损坏。
对加密相关概念整理
PHP作为一门非常流行的语言,但是有时很多人会觉得PHP效率不高,也许很多人在初次使用的时候对PHP本身还不够了解,所以造成了大家对PHP运行效率低的误解。作为脚本语言,我们也不能否认PHP跟其他编译型语言效率对比。本文我们带大家看看如何来对PHP进行优化。
快速生成表格
Electron页面跳转、浏览器打开链接和打开新窗口
在使用Git的过程中,不想每次都输入用户名和密码去拉取代码,所以就需要保存这些信息,那么既然有保存了,就必须有清除功能。
Docker编译镜像出现:fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
ERROR: http://dl-cdn.alpinelinux.org/alpine/v3.12/main: temporary error (try again later)
WARNING: Ignoring APKINDEX.2c4ac24e.tar.gz: No such file or directory问题
在Mac电脑中,如何对Git的用户名和密码进行修改呢?起初不懂Mac,所以整了很久,本文将记录如何对这个进行操作,以便后期使用。