天天看点

23种设计模式之装饰者模式

一、什么时候使用装饰者模式

公司门口有一个小摊卖鸡蛋饼和肉夹馍的,有时候早上吃早餐就回去光顾一下那个小摊,点了鸡蛋饼之后往往还可以在这个基础之上增加一些配料,例如煎蛋、火腿片、生菜,每个配料额价格都不一样,不管你怎么配配料,最终价格是鸡蛋饼基础价加上每一种所选配料价格的总和.小摊的价格单如下:

23种设计模式之装饰者模式

现在有这么一个问题,不同的主体早餐加上不同的配料有不同的价钱,怎样实现了?

大多数人的第一印象可能想到的是会使用继承.

1.首先定义一个早餐基类

2.对于加煎蛋、火腿片、肉松、黄瓜丝的,分别写一个子类继承

3.对于加煎蛋又加火腿片的写一个类、对于加煎蛋又加肉松的又写一个类、对于加煎蛋又加黄瓜丝的又写一个类等

说到这里,你会发现这里四种配料就要写十几种实现类了,那如果我们的配料是二十几种或者三十几种呢,那么使用继承这种方式肯定会使我们的子类爆炸,那么要怎么解决了,答案就是使用装饰者模式.(主体是鸡蛋饼或肉夹馍,配料是煎蛋、火腿片、肉松、黄瓜丝)

二、什么是装饰者模式

装饰者模式是在已有功能的基础上,动态地添加更多功能的一种方式,这些新加的代码装饰了原有类的 核心职责或主要行为。

三、什么是装饰者模式

看看具体java代码是怎么实现的:

早餐基类(被装饰者)

public abstract class Pancake {

	public String desc = "我不是一个具体的饼";

	public String getDesc() {
		return desc;
	}

	public abstract  double price();
}
           

鸡蛋饼类(被装饰者的初始状态,有些自己的简单装饰)

public class TornCake extends Pancake {

	  public TornCake() {
	        desc = "鸡蛋饼";
	    }

	    @Override
	    public double price() {
	        return 4;
	    }

}
           

肉夹馍类(被装饰者的初始状态,有些自己的简单装饰) 

public class Roujiamo  extends Pancake {
	public Roujiamo() {
        desc = "肉夹馍";
    }

    @Override
    public double price() {
        return 6;
    }
}
           

 配料的基类(装饰者,用来对早餐基类进行多层装饰,每层装饰增加一些配料)

public abstract class Condiment  extends Pancake {

	public abstract String getDesc();

}
           

煎蛋(装饰者的第一层) 

public class FiredEgg extends Condiment {
    private Pancake pancake;
    
    public FiredEgg(Pancake pancake) {
        this.pancake = pancake;
    }

    @Override
    public String getDesc() {
        return pancake.getDesc() + ", 煎蛋";
    }

    @Override
    public double price() {
        return pancake.price() + 2;
    }
}
           

火腿片(装饰者的第二层)  

public class Ham  extends Condiment {
	  private Pancake pancake;
	    
	    public Ham(Pancake pancake) {
	        this.pancake = pancake;
	    }

	    @Override
	    public String getDesc() {
	        return pancake.getDesc() + ", 火腿片";
	    }

	    @Override
	    public double price() {
	        return pancake.price() + 1.5;
	    }

}
           

肉松(装饰者的第三层)  

public class DriedMeatFloss extends Condiment{
	
	 private Pancake pancake;
	    
	    public DriedMeatFloss(Pancake pancake) {
	        this.pancake = pancake;
	    }

	@Override
	public String getDesc() {
		
		return pancake.getDesc() + ", 肉松";
	}

	@Override
	public double price() {
		return pancake.price() + 1;
	}

}
           

黄瓜丝(装饰者的第四层)   

public class YellowCucumberSilk extends Condiment{
	
	private Pancake pancake;
	
	public YellowCucumberSilk(Pancake pancake){
		this.pancake = pancake;
	}

	@Override
	public String getDesc() {
		return pancake.getDesc() + ", 黄瓜丝";
	}

	@Override
	public double price() {
		return pancake.price() + 0.5;
	}

}
           

测试类 

public class MyTest {
	public static void main(String[] args) {
		 Pancake tornCake = new TornCake();
	        //鸡蛋饼基础价
	        System.out.println(String.format("%s ¥%s", tornCake.getDesc(), tornCake.price()));
	        
	        Pancake roujiamo = new Roujiamo();
	        roujiamo = new FiredEgg(roujiamo);
	        roujiamo = new FiredEgg(roujiamo);
	        roujiamo = new Ham(roujiamo);
	        roujiamo = new DriedMeatFloss(roujiamo);
	        roujiamo = new YellowCucumberSilk(roujiamo);
	        //我好饿
	        System.out.println(String.format("%s ¥%s", roujiamo.getDesc(), roujiamo.price()));
	}
}
           

结果 

23种设计模式之装饰者模式

四、装饰者模式优缺点

优点:

1、装饰者模式可以提供比继承更多的灵活性

2、可以通过一种动态的方式来扩展一个对象的功能、在运行时选择不同的装饰器,从而实现不同的行为.

3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。

  4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

缺点:

  1、会产生很多的小对象,增加了系统的复杂性

  2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

参考博客:https://blog.csdn.net/qq_38157516/article/details/79852804

继续阅读