装饰模式(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("装饰===》裤子");
}
}
运行结果:
===================只装饰衣服===================
张三 的装饰
装饰===》衣服
===================装饰衣服的基础上再装饰裤子===================
张三 的装饰
装饰===》衣服
装饰===》裤子
有时候我们并不想让自己的应用能多次进行启动,所以本文主要讲解下如何限制Electron的应用多次被启动。
线性表是最基本、最简单、也是最常用的一种数据结构,一个线性表是n个具有相同特性的数据元素的有限序列。
grep命令是常用个一个命令。能够从文本文件或管道数据流中筛选匹配的行及数据,如果使用正则表达式进行一起使用,功能会更加强大。
对加密相关概念整理
Nginx作为使用量非常大的Web服务器,但是如果遇到一个访问量比较大的网站,其访问日志会快速的进行增长,如果一直将所有的访问日志存放在一个文件中肯定是不对的,所以我们就需要对访问量大的访问日志进行分割,然后按照一定的时间删除不需要的日志文件。
快速生成表格
在使用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,所以整了很久,本文将记录如何对这个进行操作,以便后期使用。