现在又这么一个场景
一家饭店经营多年后,终于开出了第100家房间,但是现在面临一个问题!就是菜单的更新,如果菜单中一个菜的更改的话,那么就需要更改所有的菜单。
简单的说家店有10本菜谱,那么100家就需要更新10*100,那是一个很恐怖的数据!
那怎么办呢,这个时候就需要设计一套电子菜单了!他们雇佣
了BigSoft公司的精英来开发这套系统!
好,项目就紧张的开始了,前期的需求调研,评估,UC的形成,架构的设计,详细设计。。。。
本来认为是一个很简单的系统,设计时碰到了一个问题!因为这家店有一道招牌菜---鸡。
这个鸡的性别可以分为 公鸡,母鸡。它们的价格是不一样的
但是这个鸡的来源又可以分为 中国产,日本产,不同产地的价格也是不一样的!
那这个菜单应该怎么设计呢。 是 鸡 ---- 中国公鸡,中国母鸡,日本公鸡,日本母鸡?
![](https://i-blog.csdnimg.cn/blog_migrate/69053c9faab2ee33f483c98e437b8a71.jpeg)
这样的话,将来又增加了来源美国鸡,若是鸡有了中性鸡呢?这些情况如何考虑?还是继续添加各种子类吗?
好吧!这个时候怎么办呢?伟大的BigSoft公司的精英们面对这点小问题当然是没问题了
就是采用了装饰模式,这里对于装饰模式的解释还是欠缺:
![](https://i-blog.csdnimg.cn/blog_migrate/091bfe390490c1556e1d8570a8a90418.jpeg)
看代码;Chickren,就是被装饰的统一对象
package com.test.test.decoration;
public abstract class Chickren {
String desc;
/* empty implement
* @see com.test.test.decoration.Chickren#cost()
*/
public abstract int cost();
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
公鸡:
package com.test.test.decoration;
public class Cock extends Chickren {
public Cock(){
desc = "this is a cock,and it's price is $1.2";
}
@Override
public int cost() {
return 12;
}
}
母鸡:
package com.test.test.decoration;
public class Hen extends Chickren {
public Hen(){
desc = "this is a hen ";
}
@Override
public int cost() {
return 10;
}
}
装饰类:
package com.test.test.decoration;
public abstract class DecorationChickren extends Chickren{
public abstract String getDesc();
}
装饰者:
中国来的鸡
package com.test.test.decoration;
/**
* notice:
* price is 15$
* desc: a hen from guangdong province which is so beautiful ,and it price is just 15$.
* you just wait what ,come on baby !
* only one day, if you lost this time ,you will never forgive youself forever!
*
* @author inter12
*
*/
public class ChinaChickren extends DecorationChickren{
private volatile Chickren chickren; //这里声明为 volatile很关键!
public ChinaChickren(Chickren chickren){
this.chickren = chickren;
}
@Override
public int cost() {
return chickren.cost() + 15; //具体的调用方式
}
@Override
public String getDesc() {
return chickren.getDesc() + "and it's not a hen ! also a china chickren! ";
}
}
日本来的鸡:
package com.test.test.decoration;
/**
* price is $10
* desc :a chickren from japan,so delicious
* @author inter12
*
*/
public class JapanChickren extends DecorationChickren {
public Chickren chick; //注意,这里还是持有一个最初的父类接口,这样就可以做到随意的多级装饰
public JapanChickren(Chickren chick) {
this.chick = chick;
}
@Override
public String getDesc() {
return chick.getDesc()+"my god ,how delicious the chickren is!";
}
public int cost() {
return chick.cost() + 10;
}
}
购买的人来了:
package com.test.test.decoration;
public class ChickrenBuyer {
public static void main(String[] args) {
//调用方式一
// Chickren chickren = new Hen();
// chickren = new ChinaChickren(chickren);
//调用方式二
Chickren chickren = new ChinaChickren(new Hen());
System.out.println("price:" + chickren.cost());
System.out.println("desc:" + chickren.getDesc());
chickren = new JapanChickren(chickren);
System.out.println("price:" + chickren.cost());
System.out.println("desc:" + chickren.getDesc());
}
}
是不是很熟悉的看到了java.io中的组合方式呢
这里做的不好的是 每个装饰的子类都有持有一个 Chickren对象,准确的应该是装饰类持有一个chickren对象,调用父类的构造方法
只改造了装饰者部分即可
下面的是改造版本:
package com.test.test.decoration;
public abstract class DecorationChickren extends Chickren {
protected volatile Chickren chick;
public abstract String getDesc();
public DecorationChickren(Chickren chickren) {
this.chick = chickren;
}
public Chickren getChickren() {
return chick;
}
public void setChickren(Chickren chickren) {
this.chick = chickren;
}
}
具体的装饰l;
package com.test.test.decoration;
/**
* notice:
* price is 15$
* desc: a hen from guangdong province which is so beautiful ,and it price is just 15$.
* you just wait what ,come on baby !
* only one day, if you lost this time ,you will never forgive youself forever!
*
* @author inter12
*
*/
public class ChinaChickren extends DecorationChickren{
public ChinaChickren(Chickren chickren){
super(chickren);
}
@Override
public int cost() {
return chick.cost() + 15;
}
@Override
public String getDesc() {
return chick.getDesc() + "and it's not a hen ! also a china chickren! ";
}
}
日本鸡:
package com.test.test.decoration;
/**
* price is $10
* desc :a chickren from japan,so delicious
* @author inter12
*
*/
public class JapanChickren extends DecorationChickren {
public JapanChickren(Chickren chick) {
super(chick);
}
@Override
public String getDesc() {
return chick.getDesc()+"my god ,how delicious the chickren is!";
}
public int cost() {
return chick.cost() + 10;
}
}
总结:
1.适用于多维的系统,例如本案中就是个很经典例子。做菜,主料是鸡煲,鸡可以选择不同国家的鸡,鸡又可以采用不同的烧法,清蒸,红烧等。那么鸡和烧法就是两个维度,这样的情况下就可以猜装饰模式,在一个前提下,将不同的行为装饰上去。
2.语法结构上,一个抽象的主对象 一个抽象的装饰类,持有一个父类接口对象,所有继承装饰类的对象都必须持有父类接口引用,这样保证该继承路线的对象都能得到装饰!
3.装饰模式意味这一群装饰对象,并且反应了被装饰组件的类型。
4.装饰者会导致设计中出现许多小对象,如果过度使用,会让系统变的很复杂!
5.动态的将责任附加到对象上,是区别于继承的另一种方式!