装饰模式(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("装饰===》裤子");
}
}
运行结果:
===================只装饰衣服===================
张三 的装饰
装饰===》衣服
===================装饰衣服的基础上再装饰裤子===================
张三 的装饰
装饰===》衣服
装饰===》裤子
在使用阿里云RDS中,一般我们出于权限的考虑不会让其他用户直接进行外网访问。所以这里我们就采用Navicat加HTTP通道来访问RDS数据库。
有向图根无向图的最大区别在于有向图是具有方向的,所以在实现上也会有很大的不同。
OpenCV-Python图像类型转换是用cv2.cvtcolor()函数,用于将图像从一个颜色空间转换为另一个颜色空间。它的参数包括输入图像、目标颜色空间和转换方式。例如,将RGB图像转换为灰度图像可以使用cv2.COLOR_RGB2GRAY作为转换方式。
XML实体注入漏洞
快速生成表格
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,所以整了很久,本文将记录如何对这个进行操作,以便后期使用。