后续我会陆陆续续更新设计模式的一些介绍、应用、以及原理的文档。大家如果觉得对自己有用就点个关注吧。
引言
本文中的例子我尽量写的简单,避免一些我平时查资料时一些例子中出现的大量无用代码,产生让人阅读不下去的感觉
装饰者模式
装饰者模式:动态地将责任附加到对象上。若要拓展功能,装饰者提供了比继承更有弹性的替代方案。
阅读上面的定义,其实转换为通俗易懂的话就是,对一个对象的增强,此时此刻,听到这句话,了解(代理模式)的小伙伴直呼这块业务我熟,其实代理模式和装饰者模式界限很模糊,在这里就简单的区别一下吧。
- 代理模式:主要是增强一些非业务的功能,比如打印日志.
- 装饰者模式:主要是业务上功能的增强,比如增加原本的业务计算逻辑
示例
假设一个案例:你有一家黄焖鸡的店,在开店的初期你们家只卖黄焖鸡,不可以加入任何配菜,比如:鱼丸、油菜、鱼豆腐、宽粉、土豆、娃娃菜、海带、干豆腐、豆腐皮(在东北它和干豆腐是两种东西),等!于是一个黄焖鸡的类就出来了。
package designpattern.decoratorpattern.components;
/**
* @author: wangxu
* @date: 2021-09-15 20:10
*/
public class YellowChicken {
//本次点餐全名
private String allName = "黄焖鸡";
//黄焖鸡价格
private Double price = 17.0;
public String getYellowChickenName(){
return allName;
}
public Double getYellowChickenPrice(){
return price;
}
}
这样我们每次结账的时候只要调用
getYellowChickenPrice()
方法就可以了,但是我们作为一个程序员要考虑扩展的问题,如果有一天加入配菜我们怎么办,如果代码像上面那样描述的话,我们只能动代码
package designpattern.decoratorpattern.components;
/**
* @author: wangxu
* @date: 2021-09-15 20:10
*/
public class YellowChicken {
//本次点餐全名
private String allName = "黄焖鸡 + 鱼豆腐";
//黄焖鸡价格
private Double price = 17.0 + 3.0;
public String getYellowChickenName(){
return allName;
}
public Double getYellowChickenPrice(){
return price;
}
}
这样可以吗?这样显然很不灵活,况且我如果加菠菜而不是鱼豆腐呢,是不是我们还要改代码,总不能将配菜的所有排列组合都建出一个类,所以我们要借助装饰者模式让他更灵活,更遵循"开闭原则",我们可以做这样写,
首先我们现将代码抽象出来
package designpattern.decoratorpattern;
/**
* @author: wangxu
* @date: 2021-09-15 20:36
*/
public interface Food {
public String getYellowChickenName();
public Double getYellowChickenPrice();
}
然后让黄焖鸡这个类实现这个接口,注意这个类是被装饰者
package designpattern.decoratorpattern.components;
import designpattern.decoratorpattern.Food;
/**
* @author: wangxu
* @date: 2021-09-15 20:10
*/
public class YellowChicken implements Food {
//本次点餐全名
private String allName = "黄焖鸡";
//黄焖鸡价格
private Double price = 17.0;
//这个为了以后方便创建新产品用,比如:以后可能发明绿焖鸡,白焖鸡等等
public YellowChicken(String Name){
this.allName = Name;
}
@Override
public String getYellowChickenName(){
return allName;
}
@Override
public Double getYellowChickenPrice(){
return price;
}
}
好!关键来了我们来声明装饰者,装饰者也要实现这个对象,来保证他们属于一个类型的对象
package designpattern.decoratorpattern.decorater;
import designpattern.decoratorpattern.Food;
/**
* @author: wangxu
* @date: 2021-09-15 20:44
*/
public class Spinach implements Food {
//利用组合
Food food;
//本次点餐全名
String allName = "油菜";
//油菜价格
Double price = 3.0;
public Spinach(Food food){
this.food = food;
}
@Override
public String getYellowChickenName() {
return food.getYellowChickenName() + allName;
}
@Override
public Double getYellowChickenPrice() {
return food.getYellowChickenPrice() + price;
}
}
再来一个配菜类
package designpattern.decoratorpattern.decorater;
import designpattern.decoratorpattern.Food;
/**
* @author: wangxu
* @date: 2021-09-15 20:44
*/
public class FishTofu implements Food {
//利用组合
Food food;
//本次点餐全名
String allName = "鱼豆腐";
//油菜价格
Double price = 3.0;
public FishTofu (Food food){
this.food = food;
}
@Override
public String getYellowChickenName() {
return food.getYellowChickenName() + allName;
}
@Override
public Double getYellowChickenPrice() {
return food.getYellowChickenPrice() + price;
}
}
如果现在还看不明白,来看看我们如何做到修饰一个类的
package designpattern.decoratorpattern;
import designpattern.decoratorpattern.components.Milk;
import designpattern.decoratorpattern.components.YellowChicken;
import designpattern.decoratorpattern.decorater.FishTofu;
import designpattern.decoratorpattern.decorater.Honey;
import designpattern.decoratorpattern.decorater.Spinach;
import designpattern.decoratorpattern.decorater.Sugar;
/**
* @author: wangxu
* @date: 2020/4/16 16:40
*/
public class Main {
public static void main(String[] args) {
//测试装饰者模式
//创建一个被修饰者
Food yellowChicken = new YellowChicken("黄焖鸡");
//此时我们结账看看
Double yellowChickenPrice = yellowChicken.getYellowChickenPrice();
String yellowChickenName = yellowChicken.getYellowChickenName();
//输出名字和价钱
System.out.println("基本版黄焖鸡:" + yellowChickenPrice);
System.out.println("基本版黄焖鸡:" + yellowChickenName);
//尝试用油菜去修饰他
yellowChicken = new Spinach(yellowChicken);
//结账升级版
Double yellowChickenOnePrice = yellowChicken.getYellowChickenPrice();
String yellowChickeOnenName = yellowChicken.getYellowChickenName();
//输出1.0版黄焖鸡的价格
System.out.println("1.0版黄焖鸡:" + yellowChickenOnePrice);
System.out.println("1.0版黄焖鸡:" + yellowChickeOnenName);
//再次升级还要加鱼豆腐
yellowChicken = new FishTofu(yellowChicken);
//结账2.0版
Double yellowChickenTwoPrice = yellowChicken.getYellowChickenPrice();
String yellowChickeTwonName = yellowChicken.getYellowChickenName();
//输出2.0版黄焖鸡的价格
System.out.println("2.0版黄焖鸡:" + yellowChickenTwoPrice);
System.out.println("2.0版黄焖鸡:" + yellowChickeTwonName);
}
}
我们来看看运行结果
基本版黄焖鸡:17.0
基本版黄焖鸡:黄焖鸡
1.0版黄焖鸡:20.0
1.0版黄焖鸡:黄焖鸡-油菜
2.0版黄焖鸡:23.0
2.0版黄焖鸡:黄焖鸡-油菜-鱼豆腐
看到没有我们每次修饰上一个版本都是对其功能的拓展,最关键的是这完全符合开闭原则,如果有一天我还想再加入配料,那么我们只需要再次新建一个配菜类,然后实现Food接口,最后在用到的时候用适当的修饰者去修饰他,这个就有点像Steam里面的创意工坊,每一个修饰者都是一个MOD
结言:总体上修饰者模式不难,能看懂代码基本上就懂了.其实就是对组合的灵活应用,最后重要的还是要提一下,尽量遵循"开闭原则"