装饰器模式java实现,Java设计模式之装饰器模式

本文探讨了装饰模式在解决对象功能扩展问题上的应用,对比了继承与装饰模式的区别。通过实例展示了如何使用装饰模式实现坦克游戏中的坦克能力动态增强,如防护罩、子弹和石墙等效果。装饰模式避免了因功能组合导致的大量子类问题,实现了运行时动态扩展功能,并符合面向对象设计原则。总结了装饰模式的适用场景和优势,强调其在动态添加和撤销对象功能方面的灵活性。
摘要由CSDN通过智能技术生成

介绍:

在软件系统中,我们有时候需要对对象的功能进行扩展,继承虽然能够解决此类问题,但是由于继承本身的一些缺点使得扩展不能动态的进行,并且面对功能扩展间的组合,使用继承会使得子类急剧膨胀。装饰模式正是用来解决这类问题的,对对象功能进行任意的扩展而不用担心类继承所带来的膨胀。

现实中的例子:

“疯狂坦克”,我想大家都玩过吧,每一关中都会随机爆出一些可吃的东西,譬如防护罩:坦克吃了,增强抗打能力;譬如子弹:坦克吃了,发射子弹的速度快了;譬如石墙:坦克吃了可以打碎石墙……

解决方案:

如果叫我实现这些功能(防护罩:坦克吃了,增强抗打能力;譬如子弹:坦克吃了,发射子弹的速度快了;譬如石墙:坦克吃了可以打碎石墙),我该如何实现呢?

方案一:

思路:很显然,不管坦克吃了什么东西变成什么东西,它最终还是一个坦克。只不过根据所吃东西的不同发射子弹后产生的效果不同而已。那么继承无疑是很好的选择。

类图:

0818b9ca8b590ca3270a3433284dd417.png

代码片段

public abstract class Itank

{

public int HP;

public  string Name;

public Itank(string name)

{

this.Name = name;

}

public abstract void Shot(Itank destination);

public virtual void BeAttacked(int hp)

{

this.HP -= hp;

Console.WriteLine(string.Format("{0} is Attacked;Hp is {1}",Name, HP));

}

}

public class CommonTank:Itank

{

public CommonTank(string name):base(name)

{

this.HP = 100;

}

public override void BeAttacked(int hp)

{

base.BeAttacked(hp);

}

public override void Shot(Itank destination)

{

Console.WriteLine(string.Format("{0} shot {1}", Name, destination.Name));

destination.BeAttacked(20);

}

}

public class SpecialTank:Itank

{

public SpecialTank(string name):base(name)

{

this.HP = 150;

}

public override void BeAttacked(int hp)

{

base.BeAttacked(hp);

}

public override void Shot(Itank destination)

{

Console.WriteLine(string.Format("{0} shot {1}", Name, destination.Name));

destination.BeAttacked(50);

}

}

public class CommonlHoodTank:Itank

{

public CommonlHoodTank(string name)

: base(name)

{

this.HP = 300;

}

public override void BeAttacked(int hp)

{

base.BeAttacked(hp);

}

public override void Shot(Itank destination)

{

Console.WriteLine(string.Format("{0} shot {1}", Name, destination.Name));

destination.BeAttacked(20);

}

}

class Program

{

static void Main(string[] args)

{

CommonTank commonTank1 = new CommonTank("CommonTank1");

CommonTank commomTank2 = new CommonTank("CommonTank2");

commonTank1.Shot(commomTank2);

Console.WriteLine("#####################################");

SpecialTank specialTank1 = new SpecialTank("SpecialTank1");

commonTank1.Shot(specialTank1);

Console.WriteLine("#####################################");

CommonlHoodTank commonlHoodTank1 = new CommonlHoodTank("CommonlHoodTank1");

commonTank1.Shot(commonlHoodTank1);

}

}

分析:如上代码,类CommonTank:普通坦克,SpecialTank:重型坦克。普通坦克吃了防护罩就需要生成新类:CommonlHoodTank。

普通坦克吃了子弹就需要生成新类:CommonBulletTank。普通坦克既吃了防护罩又吃了子弹就需要生成新类:CommonHoodBulletTank......

显然随着吃的东西的不同就需要生成不同的坦克子类。

你可以认为吃了不同的东西后变成了新的坦克(用新类表示新坦克)以此来表示新的能力,但是子类复子类,子类何其多!!!不只是如此,坦克的新功能是随着吃的东西的不同而动态获得的,所以无需像继承一样在编译时就知道其能力。基于此,设计第二套方案。

方案二:

思路:坦克吃了东西后,其能力加强了,但是本质还是该坦克而不是新坦克。

类图

0818b9ca8b590ca3270a3433284dd417.png

代码片段

如上代码所示:不仅解决了子类多得问题,也解决了动态添加功能的问题。这就是装饰者模式之精髓。

适用性

在以下情况下应当使用装饰模式:

1.需要扩展一个类的功能,或给一个类增加附加责任。

2.需要动态地给一个对象增加功能,这些功能可以再动态地撤销。

3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。

总结:

Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。

与简单继承的区别例子:

吃了子弹,吃了石墙,吃了防护罩。如果把这3种情况进行组合会有7种情况。1:吃了子弹,2:吃了石墙,3:吃了防护罩,4:吃了子弹、石墙,5:吃了子弹、防护罩,6:吃了石墙、防护罩,7:吃了石墙、防护罩、子弹。用继承来考虑需要生成7个类,但是用Decorator进行组合只需3个类:子弹Decorator、石墙Decorator、防护罩Decorator,这三个类进行相互组合就可以达到1楼的要求了。譬如表示吃了石墙、子弹、防护罩可以这样表示:Itank tank=new 子弹Decorator(new 石墙Decorator(new 防护罩Decorator(坦克1))),达到了为坦克1添加了3种能力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值