(截图来自百度汉语)
就这个词,已经快解释清楚“装饰模式”是什么东西了。
装饰模式:动态的将新功能附加到对象上。
怎么去动态添加?
其实是通过套娃实现的。
而且,没有什么附加功能是套娃解决不了的,如果不行,那就套两层。
我就,模拟养成养魔法鱼,做例子来讲一下。
首先咱们建个鱼的父类。
这是类的作用相当于管道,把主体类和各个装饰类链接起来。
package 装饰者模式;
public abstract class AboutFish {
public AboutFish obj;
public String des;
private float price = 0.0f;
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
/**
* 计算费用的抽象方法,子类实现
* @return
*/
public abstract float cost();
}
然后写魔法鱼类
这个类是主体类,所有的装饰都是给他用的。
package 装饰者模式;
public class Fish extends AboutFish {
public Fish() {
setDes("魔法鱼鱼卵");
setPrice(10.0f);
}
@Override
public float cost() {
return super.getPrice();
}
}
到现在,还没有用到装饰。
我们直接开始模拟养成魔法鱼。在过程中使用、讲述装饰模式。
package 装饰者模式;
public class Me {
public static void main(String[] args) {
// 购买鱼卵
AboutFish fish = new Fish();
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“魔法鱼鱼卵 X1”,有“水”就可以孵化鱼卵了,快去寻找“水”吧!");
System.out.println("-----");
}
}
运行结果:
已经花了:10.0
魔法鱼鱼卵
已获得“魔法鱼鱼卵 X1”,有“水”就可以孵化鱼卵了,快去寻找“水”吧!
-----
我们开始找水吧!(准备好,开始套娃了)
首先写个装饰抽象类(所有抽象类的父类),接上管道(继承鱼的父类)
package 装饰者模式;
public class Decorator extends AboutFish{
public Decorator(AboutFish obj) {
this.obj=obj;
}
@Override
public float cost() {
return super.getPrice()+obj.cost();
}
@Override
public String getDes() {
return obj.getDes();
}
}
然后写水类(装饰类)
package 装饰者模式;
public class Water extends Decorator{
public Water(AboutFish obj) {
super(obj);
setDes("水");
setPrice(0.0f);
}
}
开始孵化吧!
package 装饰者模式;
public class Me {
public static void main(String[] args) {
// 购买鱼卵
AboutFish fish = new Fish();
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“魔法鱼鱼卵 X1”,有“水”就可以孵化鱼卵了,快去寻找“水”吧!");
System.out.println("-----");
// 获得水
fish = new Water(fish);
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“水”,请尽快孵化吧");
System.out.println("-----");
System.out.println("开始孵化...");
fish.obj.des="小鱼苗";
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("孵化成功,赶快给小鱼苗找点吃的吧!");
}
}
运行结果:
已经花了:10.0
魔法鱼鱼卵
已获得“魔法鱼鱼卵 X1”,有“水”就可以孵化鱼卵了,快去寻找“水”吧!
-----
已经花了:10.0
魔法鱼鱼卵
已获得“水”,请尽快孵化吧
-----
开始孵化...
已经花了:10.0
小鱼苗
孵化成功,赶快给小鱼苗找点吃的吧!
到此我们已经装饰了一次了。
继续给小鱼苗寻找食物吧(装饰类、又套一层娃)。
package 装饰者模式;
public class 脱壳丰年虾卵__小鱼苗食物 extends Decorator{
public 脱壳丰年虾卵__小鱼苗食物(AboutFish obj) {
super(obj);
setDes("脱壳丰年虾卵");
setPrice(5.0f);
}
}
开始喂食吧。
package 装饰者模式;
public class Me {
public static void main(String[] args) {
// 购买鱼卵
AboutFish fish = new Fish();
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“魔法鱼鱼卵 X1”,有“水”就可以孵化鱼卵了,快去寻找“水”吧!");
System.out.println("-----");
// 获得水
fish = new Water(fish);
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“水”,请尽快孵化吧");
System.out.println("-----");
System.out.println("开始孵化...");
fish.obj.des="小鱼苗";
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("孵化成功,赶快给小鱼苗找点吃的吧!");
// 获得脱壳丰年虾卵
fish = new 脱壳丰年虾卵__小鱼苗食物(fish);
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“脱壳丰年虾卵”,请喂食小鱼苗,让它快快长大吧");
System.out.println("-----");
System.out.println("开始喂食..");
fish.obj.obj.des="幼鱼";
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println(".脱离幼苗期,成为幼鱼,幼鱼得吃水蚤!");
}
}
运行结果:
已经花了:10.0
魔法鱼鱼卵
已获得“魔法鱼鱼卵 X1”,有“水”就可以孵化鱼卵了,快去寻找“水”吧!
-----
已经花了:10.0
魔法鱼鱼卵
已获得“水”,请尽快孵化吧
-----
开始孵化...
已经花了:10.0
小鱼苗
孵化成功,赶快给小鱼苗找点吃的吧!
已经花了:15.0
小鱼苗
已获得“脱壳丰年虾卵”,请喂食小鱼苗,让它快快长大吧
-----
开始喂食..
已经花了:15.0
幼鱼
.脱离幼苗期,成为幼鱼,幼鱼得吃水蚤!
装饰两次了。
找水蚤吧(装饰类、双套一层娃)。
package 装饰者模式;
public class 水蚤__幼鱼食物 extends Decorator{
public 水蚤__幼鱼食物(AboutFish obj) {
super(obj);
setDes("水蚤");
setPrice(10.0f);
}
}
开始喂鱼:
package 装饰者模式;
public class Me {
public static void main(String[] args) {
// 购买鱼卵
AboutFish fish = new Fish();
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“魔法鱼鱼卵 X1”,有“水”就可以孵化鱼卵了,快去寻找“水”吧!");
System.out.println("-----");
// 获得水
fish = new Water(fish);
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“水”,请尽快孵化吧");
System.out.println("-----");
System.out.println("开始孵化...");
fish.obj.des="小鱼苗";
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("孵化成功,赶快给小鱼苗找点吃的吧!");
// 获得脱壳丰年虾卵
fish = new 脱壳丰年虾卵__小鱼苗食物(fish);
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“脱壳丰年虾卵”,请喂食小鱼苗,让它快快长大吧");
System.out.println("-----");
System.out.println("开始喂食..");
fish.obj.obj.des="幼鱼";
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println(".脱离幼苗期,成为幼鱼,幼鱼得吃水蚤!");
// 获得水蚤
fish = new 水蚤__幼鱼食物(fish);
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已获得“水蚤”,请喂食幼鱼,让它快快长大吧");
System.out.println("-----");
System.out.println("开始喂食...脱离幼鱼期,成为成鱼");
fish.obj.obj.obj.des="成鱼";
System.out.println("已经花了:"+fish.cost());
System.out.println(fish.getDes());
}
}
运行结果:
已经花了:10.0
魔法鱼鱼卵
已获得“魔法鱼鱼卵 X1”,有“水”就可以孵化鱼卵了,快去寻找“水”吧!
-----
已经花了:10.0
魔法鱼鱼卵
已获得“水”,请尽快孵化吧
-----
开始孵化...
已经花了:10.0
小鱼苗
孵化成功,赶快给小鱼苗找点吃的吧!
已经花了:15.0
小鱼苗
已获得“脱壳丰年虾卵”,请喂食小鱼苗,让它快快长大吧
-----
开始喂食..
已经花了:15.0
幼鱼
.脱离幼苗期,成为幼鱼,幼鱼得吃水蚤!
已经花了:25.0
幼鱼
已获得“水蚤”,请喂食幼鱼,让它快快长大吧
-----
开始喂食...脱离幼鱼期,成为成鱼
已经花了:25.0
成鱼
接下来还有性成熟、交尾、产卵、衰老、死亡,等等。
你可以接着又、双继续叒、叕的套下去
今天咱们的娃,就先套到这里,啊不对,咱们的鱼,就先养到这里吧。
毕竟它是一条工具鱼。养到这里,就够我们理解装饰模式了。
这是原理图:
(关于向上转型,不了解的可以看我的另一篇博客学习:Java知识扫盲——向上转型(类向上转型、接口向上转型)以及向上转型的优势、灵活运用)
这是串起来以后的效果图:
通过这种无限套娃,让本来的Fish可以经过多次修饰,动态的添加功能。
到现在,我想大家已经理解什么是装饰模式了。
如大家所见,扩展性非常好,只要套下去就可以了。。。