Java中关于Decorator(装饰),Delegation(委派),Proxy(代理)的一些理解

        在正式学习4.2节关于委派的内容之前,我对于选择何种方式实现Lab3以提高代码的复用性感到十分困惑。直到我查阅到这样一篇博客:Java设计模式 — Decorator(装饰),Delegation(委托) ,Proxy(代理),有了一些想法。这篇博客中的例子对于理解装饰,委派和代理有很大的帮助,也能加深对课程中4.2节相关知识的理解,感兴趣的小伙伴可以直接阅读原博客,当然我下面也会依据我的理解进行改编。


我们先来一个生动形象的例子:众所周知,哈工大即将迎来百年校庆,届时会有许多校友回到母校参加。为了选择合适的交通工具来哈尔滨,需要建造一个票价查询系统。我们姑且把来哈尔滨的交通工具框定在火车和飞机这两种类型上面,但是会发现不管是火车还是飞机都有不同的舱位选择(比如飞机有头等舱,商务舱和经济舱)。如果火车和飞机各有三种仓位,组合一下就会出现六个票种。如果我们为每一个票种写一个单独的类,那么工程量巨大并且不可避免一些代码可复用性低造成的风险。因此,我们就需要进入我们的第一个主题,Decorator(装饰)。
一. Decorator(装饰)

        装饰顾名思义就是要给一个我们已有的东西加一些点缀,使它与之前有所不同。例如一位校友在来哈尔滨的行程中选择了乘坐飞机的经济舱,但是他临时改变了主意,将经济舱升为了商务舱,这个升舱的过程就可以视作是他给他的机票进行了装饰。下面我们来看如果运用装饰来实现不同票价表示的例子。


我们先定义一个普通的火车票和机票
// 交通工具的接口
public interface Transportation {
	public double price(); // 价格
}

// 普通的火车票
public class Train implements Transportation{
	private final double trainPrice = 100;
	
	@Override
	public double price() {
		return trainPrice;
	}
}

// 普通的飞机票
public class Plane implements Transportation{
	private final double planePrice = 500;
	
	@Override
	public double price() {
		return planePrice;
	}
}

接下里,我们要对普通的火车票和机票加一些装饰

// 装饰类
public abstract class TransDecorator implements Transportation {
	protected Transportation trans;
	
	public TransDecorator(Transportation SetTrans) {
		trans = SetTrans;
	}
	
	@Override
	public abstract double price();
}

// 头等舱
public class FirstClass extends TransDecorator{
	private final double addRate = 1.0;
	
	public FirstClass(Transportation SetTrans) {
		super(SetTrans);
	}
	
	@Override
	public double price() {
		return trans.price() * (1+addRate); //升舱需要在原有票价基础上提高
	}
}

// 商务舱
public class SecondClass extends TransDecorator{
	private final double addRate = 0.5;
	
	public SecondClass(Transportation SetTrans) {
		super(SetTrans);
	}
	
	@Override
	public double price() {
		return trans.price() * (1+addRate); //升舱需要在原有票价基础上提高
	}
}

于是,调用这些装饰,我们就能得到以下六类票:

Transportation normalPlane = new Plane(); // 经济舱飞机,500
Transportation secondClassPlane = new SecondClass(new Plane()); // 商务舱飞机,750
Transportation firstClassPlane = new FirstClass(new Plane()); // 头等舱飞机,1000
Transportation normalTrain = new Train(); // 普通火车,100
Transportation secondClassTrain = new SecondClass(new Train()); // 二等座火车,150
Transportation firstClassTrain = new FirstClass(new Train()); // 一等座火车,200

如果说,飞机和火车上还存在各种服务(比如火车上的餐车),就会出现更多种类的票价,我们可以通过加入更多的修饰来实现,这里我就不再枚举了。


那我们再回到刚才的例子中,这次我们把范围缩小一点,只取一个乘客进行讨论:HTY虽然不是校友,但是他也需要买票(什么时候能开学呐)。但是买票这种事情,不是说你上飞机的时候把钱拍到机长手里就可以的,而是要提前在网站上买好票。于是我们又要进入下一个主题,Delegation(委派)。


二. Delegation(委派)

        这也是一个很生活化的词语。当有些事情我们不想做 做不到的时候,就需要伸手委托他人帮助,这一个行为我们称之为白嫖委派。例如上课举的例子:请律师打官司等等。 所以在刚才那个例子中,HTY作为一名乘客本身买不了机票,需要借助购票网站购买机票,也就是在使用委派的操作。下面我们来看代码是如何实现的。

// 乘客接口
public interface Passengers {
	public double spend();
	public void arrival();
}

// 一名乘客
public class Passenger implements Passengers{
	private transPlotform plotform; // 委派购票平台购买
	
	public Passenger(int trans, int category) {
		plotform = new transPlotform(trans, category);
	}
	
	@Override
	public double spend() {
		return plotform.price();
	}
	
	@Override
	public void arrival() {
		System.out.printf("Arrive at HIT, spend ¥%.1f\n", spend());
	}
}

// 购票平台
public class transPlotform implements Transportation {
	Transportation trans;
	public transPlotform(int SetTrans, int SetCategory) { // SetTrans = 0(火车)/1(飞机), SetCategory = 0(普通)/1(二等)/2(一等)
		if (SetTrans == 0) trans = new Train();
		else trans = new Plane();
		if (SetCategory == 1) trans = new SecondClass(trans);
		else if (SetCategory == 2) trans = new FirstClass(trans);		
	}
	
	@Override
	public double price() {
		return trans.price();
	}
}

于是,我们可以得到下面的结果:

Passengers hty = new Passenger(1, 1); // 买了一张商务舱的机票
hty.arrival();
// out: Arrive at HIT, spend ¥750.0

我们可以看到HTY本身并没有买票,而是委托购票平台买了票,他做的是支付购票的钱。

我们还是要回到刚才的例子中来:HTY比较穷,但是更不幸的是,他还很蠢,分不清自己的钱买得起什么票。于是他需要一个人告诉他,他当前买的票是否付得起。这里就要引出我们的最后一个主题,Proxy(代理)。


三. Proxy(代理)

代理也很好理解,例如很多国外的游戏公司只精通开发游戏,而怎么在中国卖游戏,他们并不擅长,于是就需要找某讯(没有打广告)等一些公司代替他们宣传和销售。当大家看完接下来的代码后,可能会有一个困惑,代理和委派好像是一样的。其实不然,仔细比较两者的代码,你会发现:代理本身什么也不做,只是在调用被代理类的方法;而委派,是要调用自己的方法解决客户需求的。(这么一看,是不是觉得代理商都是些薅羊毛的奸商呢

// 代理类
public class smartPassenger implements Passengers {
	private Passenger passenger;
	
	public smartPassenger(Passenger SetPass) {
		passenger = SetPass;
	}
	
	@Override
	public double spend() {
		return 0;
	}
	
	@Override
	public void arrival() {
		if (passenger.spend() > 500) { //如果乘客购买的票贵于500
			System.out.println("You don't have enough money! Stay at home!");
		}
		else {
			passenger.arrival();
		}
	}
}

我们来看上面这个代理类能干什么

Passengers hty = new Passenger(1, 1); // HTY企图买一张商务舱机票
Passengers xxd = new smartPassenger((Passenger)hty); // 这时XXD突然出现,代替HTY决策一下该不该买这张票
xxd.arrival(); // 发现HTY并没有这么多钱,于是让他老老实实呆在了家里
	
hty = new Passenger(1, 0); // HTY只能重新选择了一张经济舱的机票
xxd = new smartPassenger((Passenger)hty); // XXD再次审核
xxd.arrival(); // 发现钱刚好够,于是HTY可以高高兴兴的回学校了

结论

        以上讨论的Decorator(装饰),Delegation(委派),Proxy(代理)这三种操作,在实际的代码编写中具有很大的价值,我也只是根据上文给出的原博客进行了一些改编并加入自己的理解。至于深入理解乃至熟练运用,还需要在实践中多加练习,例如正在进行的Lab3,就有很多机会运用这些操作。我也 可能在接下来的博客中介绍自己在设计Lab3中的一些想法,希望这些博客能给大家一些启发吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值