前言
前面在学习mybatis的二级缓存中,我们提到CachingExcuter,以及cache接口中用到了装饰者设计模式,那么到底什么是装饰者设计模式呢?它有什么优势呢?下面结合网吧上网的例子来看看装饰者模式如何将普通玩家装饰为人民币玩家。
装饰者模式介绍
1.装饰者类要实现真实类同样的接口
2.装饰者类内有一个真实对象的引用(可以通过装饰者类的构造器传入)
3.装饰类对象在主类中接受请求,将请求发送给真实的对象(相当于已经将引用传递到了装饰类的真实对象)
4.装饰者可以在传入真实对象后,增加一些附加功能(因为装饰对象和真实对象都有同样的方法,装饰对象可以添加一定操作在调用真实对象的方法,或者先调用真实对象的方法,再添加自己的方法)
代码展示
package com.aiqinhai;
/*
* 最原始(diaosi)的网吧上网接口
* 需要装饰的原始对象
*/
public interface PlayComputeGame {
//掏出身份证登记,付钱
public void ChargeMoney();
//打开电脑
public void turnOnTheComputer();
//吃鸡
public void eatChicken();
//整个上网吃鸡流程
public void playComputeGame();
}
上面是需要被装饰的原始接口,下面展示原始接口的直接实现类
package com.aiqinhai;
/**
* 佛系上网(其实是兜里的钱只够网费)
* 需要被装饰对象的实现类
* @author aiqinhai
*/
public class PlayComputeGameWithNothing implements PlayComputeGame{
@Override
public void ChargeMoney() {
// TODO Auto-generated method stub
System.out.println("老板,充五块钱网费!");
}
@Override
public void turnOnTheComputer() {
// TODO Auto-generated method stub
System.out.println("找个机子,操,隔壁位的小孩德玛玩的可以嘛!");
}
@Override
public void eatChicken() {
// TODO Auto-generated method stub
System.out.println("开始吃鸡!");
}
@Override
public void playComputeGame() {
// TODO Auto-generated method stub
ChargeMoney();
turnOnTheComputer();
eatChicken();
}
}
上面的上网,只是吃鸡,单纯的佛系上网,这时候肚子有点饿咋搞,没关系,我们有钱,用装饰者搞定。下面就是装饰着抽象类
package com.aiqinhai;
/**
* 装饰者
* 用钱装饰的人民币玩家
* @author aiqinhai
*/
public abstract class PlayComputerGameWithMoney implements PlayComputeGame{
private final PlayComputeGame playComputeGame;
public PlayComputerGameWithMoney(PlayComputeGame playComputeGame){
super();
this.playComputeGame=playComputeGame;
}
public void ChargeMoney(){
this.playComputeGame.ChargeMoney();
}
public void turnOnTheComputer(){
this.playComputeGame.turnOnTheComputer();
}
public void eatChicken(){
this.playComputeGame.eatChicken();
}
public void playComputeGame(){
ChargeMoney();
turnOnTheComputer();
eatChicken();
}
}
上面既然有装饰者了,那么我想来份热狗怎么说
package com.aiqinhai;
/**
* 吃热狗版上网
* @author aiqinhai
*
*/
public class PlayComputerGameWithHotDog extends PlayComputerGameWithMoney{
public PlayComputerGameWithHotDog(PlayComputeGame playComputeGame) {
super(playComputeGame);
// TODO Auto-generated constructor stub
}
public void buyHotDog(){
System.out.println("网管,来一份热狗,那个谁同款的!");
}
public void eatChicken(){
this.buyHotDog();
super.eatChicken();
}
}
有热狗没有辣条这种国民美食,怎么行!
package com.aiqinhai;
/**
* 吃辣条版本上网
* @author aiqinhai
*/
public class PlayComputerGameWithLatiao extends PlayComputerGameWithMoney{
public PlayComputerGameWithLatiao(PlayComputeGame playComputeGame) {
super(playComputeGame);
// TODO Auto-generated constructor stub
}
public void buyLatiao(){
System.out.println("网管,来包辣条!");
}
public void eatChicken(){
this.buyLatiao();
super.eatChicken();
}
}
接下来看看经过装饰着装饰之后的人民币玩家如何上网
package com.aiqinhai;
/**
* 开始人民币玩家上网模式
* (听说热狗和辣条更配哦)
* @author aiqinhai
*/
public class Client {
public static void main(String[] args) {
System.out.println("diaosi玩家装饰为人民币玩家");
PlayComputeGame playComputerGame=new PlayComputeGameWithNothing();
playComputerGame=new PlayComputerGameWithHotDog(playComputerGame);
playComputerGame=new PlayComputerGameWithLatiao(playComputerGame);
playComputerGame.playComputeGame();
System.out.println("装饰成功,唉,我这无处安放的魅力啊!");
}
}
效果如下
上面的上网已经结束了,那么如果这时候吃辣条口渴了,我想来份可乐咋搞?我们可以在写个喝可乐上网的类,去继承装饰者类,然后再在mian方法中去调用就可以了。。当然你还可以来一位陪玩小姐姐啥的,毕竟人民币玩家嘛!
总结
上面的装饰者设计模式上网的例子想必大家都懂了,那么为啥要用装饰者模式呢?在装饰者模式之前是怎么解决的呢?其实如果不适用装饰者模式,我们采用多次继承的方式,比如说我想上网的时候吃热狗,我们就用PlayComputerGameWithHotDog去继承PlayComputeGameWithNothing,我想上网的时候吃辣条,我们就用PlayComputerGameWithLatiao去继承PlayComputeGameWithNothing,那如果我想既吃热狗又吃辣条咋搞,我们可以用PlayComputerGameWithLatiao去继承已经继承PlayComputeGameWithNothing的PlayComputerGameWithHotDog类。这样就可以同时上网吃辣条和热狗了。但是如果不满足还想来位陪玩小姐姐,我就又得再继承。。。这样下去,这条继承链会变得很长很长,毕竟欲望这东西没有结束的时候,这样后期维护起来显然很费力。所以这时候的装饰者的优势就体现出来了。