引例
假设现在有鸟和猫,它们都有飞翔fly()行为,代码如下
Flyable接口
public interface Flyable {
//飞翔
void fly();
}
Bird类
public class Bird implements Flyable{
@Override
public void fly() {
System.out.println( "Bird fly!");
}
}
Cat类
public class Cat implements Flyable{
@Override
public void fly() {
System.out.println( "Cat fly!" );
}
}
测试类
public class Test {
public static void main(String[] args) {
Flyable flyable1 = new Cat();
flyable1.fly();
Flyable flyable2 = new Bird();
flyable2.fly();
}
}
执行结果
Cat fly!
Bird fly!
很简单的一个多态实现。现在我们要进行功能扩展,我们要对各个类的飞翔时间进行统计,即获得fly()方法的执行时间,要怎么实现呢?
最简单的方式是对原fly()方法进行修改,可是这违背了OCP原则。
我们可以通过子类继承父类的方式,对父类的行为进行扩展。
Bird子类
public class BirdSub extends Bird{
@Override
public void fly() {
long begin = System.currentTimeMillis();
super.fly();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end - begin)+"毫秒");
}
}
Cat子类
public class CatSub extends Cat{
@Override
public void fly() {
long begin = System.currentTimeMillis();
super.fly();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end - begin)+"毫秒");
}
}
测试类
public class Test {
public static void main(String[] args) {
Flyable flyable1 = new CatSub();
flyable1.fly();
Flyable flyable2 = new BirdSub();
flyable2.fly();
}
}
执行结果
Cat fly!
耗时0毫秒
Bird fly!
耗时0毫秒
这种功能扩展方式虽然符合OCP,没有修改之前的原代码,可是类与类的继承关系属于耦合度偏高的一种方式,并且,如果有100个类实现了Flyable接口,就要增加这100个类的子类,所以导致两个问题:
- 代码耦合度高
- 类爆炸问题
要怎么解决这个问题呢?装饰者模式可以很好的解决该问题
装饰者模式
-
装饰者模式主要解决的是,在代码松耦合的前提下,完成功能的扩展。
-
装饰者模式中有两个角色:装饰者、被装饰者
-
装饰者模式要求:装饰者与被装饰者实现同一个接口,或继承同一个抽象类
-
为什么装饰者与被装饰者要实现同一个接口呢?
- 因为实现了同一个接口之后,对于客户端程序来说,使用装饰者的时候就像在使用被装饰者一样
-
装饰者含有被装饰者的引用。(A has B)这样降低耦合度
我用比较通俗的语言来讲明白装饰者模式:
- 在上述引例中,两个类Bird和Cat,我们就把这两个类当做两只动物
- Flyable是一个接口,里面有fly()方法,所以我们把该接口当做一双翅膀
- 现在Bird和Cat实现了Flyable接口,相当于Bird和Cat获得了翅膀,它们可以飞翔
- 而我们现在要增加功能,想要获得飞翔的时间,我们就可以在翅膀上添加一个计时器,记录飞翔的时间
- 在翅膀上添加的计时器就是装饰者,而被装饰者就是Flyable
- 翅膀插在Bird上,计时器统计的是Bird飞翔时间;翅膀插在Cat上,计时器统计的是Cat飞翔时间
我们来写一下代码,Cat、Bird、Flyable都不变
装饰者FlyableDecorator类,
public class FlyableDecorator implements Flyable {
//FlyableDecorator是装饰者
//Cat、Bird、Flyable都是被装饰者
private Flyable flyable;//代表了所有的子类
public FlyableDecorator(Flyable flyable) { //给flyable传值,防止空指针
this.flyable = flyable;
}
@Override
public void fly() {
long begin = System.currentTimeMillis();
flyable.fly();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end - begin)+"毫秒");
}
}
测试类
public class Test {
public static void main(String[] args) {
Flyable flyable1 = new FlyableDecorator(new Cat());
flyable1.fly();
Flyable flyable2 = new FlyableDecorator(new Bird());
flyable2.fly();
}
}
执行结果
Cat fly!
耗时0毫秒
Bird fly!
耗时0毫秒
优化
假设我们现在又要有新功能了,要进行起飞前的准备和安全降落准备,怎么实现呢?新增一个装饰者类
并且,我们可以为所有的装饰者类提取一个抽象父类,增强代码的可扩展性
Cat、Bird、Flyable都不变
所有装饰者类的父类:FlyableDecoratorFather
public abstract class FlyableDecoratorFather implements Flyable{
private Flyable flyable;
public FlyableDecoratorFather(Flyable flyable) {//给flyable传值,防止空指针
this.flyable = flyable;
}
@Override
public void fly() {
flyable.fly();
}
}
统计飞翔时间的装饰者类FlyableDecorator
public class FlyableDecorator extends FlyableDecoratorFather{
public FlyableDecorator(Flyable flyable){
super(flyable);
}
@Override
public void fly() {
long begin = System.currentTimeMillis();
super.fly();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end - begin)+"毫秒");
}
}
起飞前的准备和安全降落准备的装饰者类LogDecorator
public class LogDecorator extends FlyableDecoratorFather{
public LogDecorator(Flyable flyable) {
super(flyable);
}
@Override
public void fly() {
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
System.out.println(sdf.format(now) + ": 起飞前的准备");
super.fly();
now = new Date();
System.out.println(sdf.format(now) + ": 安全降落");
}
}
测试类
public class Test {
public static void main(String[] args) {
Flyable flyable1 = new FlyableDecorator(new Cat());
flyable1.fly();
Flyable flyable2 = new LogDecorator(new Bird());
flyable2.fly();
}
}
执行结果
Cat fly!
耗时0毫秒
2024-08-11 17:02:40 004: 起飞前的准备
Bird fly!
2024-08-11 17:02:40 051: 安全降落
可以看到,针对不同的类,可以用不同的装饰者
装饰者模式类图
在上述例子中,各类的继承结构如图