设计模式(7) - 结构型模式之 - 装饰模式

1. 介绍

1.1 装饰器模式的介绍

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

创建了一个装饰类 去包装原有的类 在不改变 要扩展的类的前提下 提供额外功能。

1.2 适用的场景

比如有些场景,我们使用 继承的方式实现扩展,会出现类爆炸 的问题。
例如:
我现在这个面馆,有炸酱面,麻酱面。
那么我只需要定义一个抽象的面条类,
和继承面条类的炸酱面类,和麻酱面类。
这样看是没有问题。

那么需求变更来了:
现在面馆说:我现在面条可以加醋,可以加辣椒,可以两个都加。
那么为了不更改之前的代码,想,唉?这个容易,我们在扩展(3 * 2)个类不就行了。一个加醋的炸酱面,一个加辣椒的炸酱面,一个加醋和辣椒的炸酱面,然后再把这个炸酱面换成麻酱面,这又是三个类,加起来6个了。但是你想想,面馆又推出了一款面条,叫刀削面,你看看,这就9个了,如果扩展了个调料,这类写起来就更多 了,这类的个数。增加的很快。这就产生了类爆炸的问题。

此时 就引出了这个装饰模式。此模式可以解决此问题。避免类爆炸,同时还符合ocp原则。

总的来说何时使用?

  • 动态地给一个对象添加一些额外的职责
  • 并且在不想增加很多子类的情况下扩展类。

1.3 优点

装饰类和被装饰类可以独立发展,不会相互耦合
装饰模式可以动态扩展一个实现类的功能。

1.4 缺点

看起来比较复杂,不容易理解,而且,这里面有一个继承并不符合is a 的关系。

2. 类图

在这里插入图片描述

3. 代码(不重要)

3.1 Nooldes

/**
 * 面条统称抽象类
 * @author immortal
 */
abstract class Noodles {
    
    

	// 面条的描述
	private String description;
	
	public Noodles(String description) {
    
    
		this.description = description;
	}
	
	
	/**
	 * 获取价格的方法,子类去实现
	 */
	public abstract Double getPrice();
	
	/**
	 * 获取描述
	 */
	public String getDescription() {
    
    
		return this.description;
	}
	
}

3.2 Noodles 的实现 炸酱面类

/**
 * 炸酱面,为了方便理解,再加上英语不太好诠释,
 * 所以这边使用拼音缩写
 * @author immortal
 *
 */
class ZjNoodles extends Noodles {
    
    
	
	/**
	 * 父类没有无参构造,所以这边调用的是其有参构造
	 * @param description
	 */
	public ZjNoodles() {
    
    
		super("炸酱面");
	}

	/**
	 * 确定价格。7块钱,香香香
	 */
	@Override
	public Double getPrice() {
    
    
		return 7d;
	}
	
}

3.3 Noodles 的实现 麻酱面类

/**
 * 麻酱面,为了方便理解,这边使用的拼音, 英语也不好写
 * @author immortal
 *
 */
class MjNoodles extends Noodles {
    
    

	/**
	 * 父类没有无参构造,所以这边调用的是其有参构造
	 * @param description
	 */
	public MjNoodles() {
    
    
		super("麻酱面");
	}

	/**
	 * 确定价格。5块钱,我感觉这价格,我能接受。哈哈
	 */
	@Override
	public Double getPrice() {
    
    
		return 5d;
	}
	
}

3.4 调料的抽象类 (Spice)

/**
 * 面条调料抽象类,比如有 醋,辣椒, 大蒜啥的
 * 注意,这里是重点,这里虽然调料跟面条不是is a 的关系,
 * 看似不太象是能拥有继承关系,但是这个设计模式就是这样。
 * 
 * @author immortal
 *
 */
abstract class Spice extends Noodles {
    
    

	// 重点:聚合一个Noodles,并且继承一个Noodles
	// 继承的目的就是为了,装饰了这个noodles之后,其类型还是一个noodles
	// 聚合的的目的,就是为了获取 要装饰的源类
	protected Noodles noodles;
	
	public Spice(Noodles noodles) {
    
    
		super("面条调料");
		this.noodles = noodles;
	}
	
	/**
	 * 获取价格,子类来实现
	 */
	public abstract Double getPrice();
	
}

3.5 调料的实现类- 醋(Vinegar)

/**
 * 醋, 可以给面条放醋,继承调料
 * @author immortal
 */
class Vinegar extends Spice {
    
    

	public Vinegar(Noodles noodles) {
    
    
		super(noodles);
	}

	/**
	 * 这边拿到父类的 Noodles, 进行价格装饰,加醋是1块钱
	 */
	@Override
	public Double getPrice() {
    
    
		return super.noodles.getPrice() + 1.0;
	}
	
	/**
	 * 对面条进行描述的装饰,因为加了醋
	 */
	@Override
	public String getDescription() {
    
    
		return super.noodles.getDescription() + "加 醋";
	}
	
}

3.6 调料的实现类- 辣椒

/**
 * 辣椒, 可以给面条放醋,继承调料
 * @author immortal
 *
 */
class Chilli extends Spice {
    
    

	public Chilli(Noodles noodles) {
    
    
		super(noodles);
	}

	/**
	 * 加辣椒,多给1.5块钱
	 */
	@Override
	public Double getPrice() {
    
    
		return super.noodles.getPrice() + 1.5;
	}
	
	/**
	 * 装饰原有的 添加上描述
	 */
	@Override
	public String getDescription() {
    
    
		return super.noodles.getDescription() + "加了 辣椒";
	}
	
}

3.7 使用方法

public static void main(String[] args) {
    
    
	
	// 1. 来个炸酱面
	Noodles zjNoodles = new ZjNoodles();
	System.out.println(zjNoodles.getDescription());
	System.out.println(zjNoodles.getPrice());
	
	// 2. 给炸酱面放点醋
	Noodles zjVinegarNoodles = new Vinegar(zjNoodles);
	
	System.out.println(zjVinegarNoodles.getPrice());
	System.out.println(zjVinegarNoodles.getDescription());
	
	// 3. 醋不够,再放点
	Noodles zjVinegarNoodles2 = new Vinegar(zjVinegarNoodles);
	
	System.out.println(zjVinegarNoodles2.getPrice());
	System.out.println(zjVinegarNoodles2.getDescription());
	
	// 4. 放点辣椒。。。。。可以层层包装下去
	
	
}

4. 是否满足ocp?(如何扩展)

在这里插入图片描述

5. 总结

自己记录一下学习,写的很烂,也不会表达。。。。。。。

猜你喜欢

转载自blog.csdn.net/weixin_42041788/article/details/106517611