1:主题拆解
①基本介绍
②王者荣耀英雄甄姬皮肤场景
③装饰器模式的优缺点
④适用场景
⑤相关扩展
2:基本介绍
装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
装饰模式是一种用于替代继承的技术,无须定义子类即可给对象动态增加职责,使用对象之间的关联关系来代替继承关系,在装饰模式中引入了装饰类,在装饰类中既可以调用待装饰的原有类方法,还可以增加新的方法,以扩充原有的类功能。
3:王者荣耀英雄甄姬皮肤场景
下面以当前热门游戏王者荣耀英雄甄姬选择皮肤,然后开始对战来模拟
1:基础版
①英雄抽象类基类
public abstract class AbstractBaseCharacter
{
public AbstractBaseCharacter()
{
//构造函数
}
public int Id { get; set; }
public string Name { get; set; }
/// <summary>
/// 开始游戏
/// </summary>
public void Play()
{
Console.WriteLine(" 当前玩家,mylove:{0}", this.Name);
}
//秀皮肤
public abstract void Show();
}
②玩家类继承并且实现
public class ZhenjiPlay : AbstractBaseCharacter
{
//选择甄宓自动获得经典皮肤
public override void Show()
{
Console.WriteLine(" 真的,会有人选择阿宓吗?");
Console.WriteLine(" 沦陷在爱情的泡影中。");
Console.WriteLine(" 明明说好的,要永远在一起。");
Console.WriteLine(" 果然,先爱上的那个人,是输家。");
Console.WriteLine(" 获得皮肤-经典");
}
}
③上端调用
AbstractBaseCharacter zhenji = new ZhenjiPlay()
{
Id = 1,
Name = "颖宝"
};
zhenji.Show();
zhenji.Play();
分析:该版本为最基本的抽象工厂模式,对英雄的方法与属性由抽象类进行约束,子类再进行重写实现。
如果另外一个玩家,其除了经典皮肤之外又喜欢幽恒这一款皮肤,该如何处理呢。直接改玩家类势必就违反了对修改封闭的原则。
现在提供两种方式。
2:组合方式版
①添加一个组合类
public class ZhenjiPlayCombination
{
private AbstractBaseCharacter _AbstractBaseCharacter = null;
public ZhenjiPlayCombination(AbstractBaseCharacter abstractBaseCharacter)
{
this._AbstractBaseCharacter = abstractBaseCharacter;
this._AbstractBaseCharacter.Id = abstractBaseCharacter.Id;
this._AbstractBaseCharacter.Name = abstractBaseCharacter.Name;
}
public void Show()
{
this._AbstractBaseCharacter.Show();
Console.WriteLine(" 获得皮肤-幽恒");
}
public void Play()
{
this._AbstractBaseCharacter.Play();
}
}
②上端调用
AbstractBaseCharacter zhenji = new ZhenjiPlay()
{
Id = 1,
Name = "颖宝"
};
ZhenjiPlayCombination zhenjiPlayCombination = new ZhenjiPlayCombination(zhenji);
zhenjiPlayCombination.Show();
zhenjiPlayCombination.Play();
分析:采用组合的方式,实现了功能的扩展,并且没有对原有的类做更改,遵循了对修改封闭对扩展开放。
3:继承方式版
①添加一个继承类
public class ZhenjiPlay幽恒 : ZhenjiPlay
{
public override void Show()
{
base.Show();
Console.WriteLine(" 获得皮肤-幽恒");
}
}
②上端调用
ZhenjiPlay幽恒 zhenjiPlay幽恒 = new ZhenjiPlay幽恒()
{
Id = 1,
Name = "颖宝"
};
zhenjiPlay幽恒.Show();
zhenjiPlay幽恒.Play();
分析:采用继承的方式,同样是在未更改原有封装的前提下实现了业务功能的扩展
4:装饰器模式版本
需求:随着玩家的增加,特别是土豪玩家或者犯有皮肤收藏强迫症的小菇凉加入,基于上面的继承与组合的方式,不可能每获得一个皮肤就增加一种组合或者继承。特别是不同的玩家对皮肤的喜爱程度不一样,购买顺序也不一样,这样无论是组合还是继承的方式来实现,对应的类都会成爆炸式增长。
①抽象类基类
public abstract class AbstractBaseCharacter
{
public AbstractBaseCharacter()
{
//构造函数
}
public int Id { get; set; }
public string Name { get; set; }
/// <summary>
/// 开始游戏
/// </summary>
public void Play()
{
Console.WriteLine(" 当前玩家,mylove:{0}", this.Name);
}
//秀皮肤
public abstract void Show();
}
②组合+继承的方式继承并且实现基类
public class BaseZhenJi : AbstractBaseCharacter
{
private AbstractBaseCharacter _AbstractBaseCharacter = null;
public BaseZhenJi(AbstractBaseCharacter AbstractBaseCharacter)
{
this._AbstractBaseCharacter = AbstractBaseCharacter;
this.Id = _AbstractBaseCharacter.Id;
this.Name = _AbstractBaseCharacter.Name;
}
//重写
public override void Show()
{
this._AbstractBaseCharacter.Show();
}
}
③获取各种皮肤类的实现
public class ZhenJiWith_冰雪圆舞曲 : BaseZhenJi
{
public ZhenJiWith_冰雪圆舞曲(AbstractBaseCharacter abstractBaseCharacter)
: base(abstractBaseCharacter)
{
}
public override void Show()
{
base.Show();
Console.WriteLine(" 获得皮肤-冰雪圆舞曲");
}
}
public class ZhenJiWith_花好人间 : BaseZhenJi
{
public ZhenJiWith_花好人间(AbstractBaseCharacter abstractBaseCharacter)
: base(abstractBaseCharacter)
{
}
public override void Show()
{
base.Show();
Console.WriteLine(" 获得皮肤-花好人间");
}
}
public class ZhenJiWith_游园惊梦 : BaseZhenJi
{
public ZhenJiWith_游园惊梦(AbstractBaseCharacter abstractBaseCharacter)
: base(abstractBaseCharacter)
{
}
public override void Show()
{
base.Show();
Console.WriteLine(" 获得皮肤-游园惊梦-mylove");
}
}
public class ZhenJiWith_幽恒 : BaseZhenJi
{
public ZhenJiWith_幽恒(AbstractBaseCharacter abstractBaseCharacter)
: base(abstractBaseCharacter)
{
}
public override void Show()
{
base.Show();
Console.WriteLine(" 获得皮肤-幽恒");
}
}
④基础玩家类
基础玩家自带经典皮肤,并且会发出人生感叹。。。
public class ZhenjiPlay : AbstractBaseCharacter
{
//选择甄宓自动获得经典皮肤
public override void Show()
{
Console.WriteLine(" 真的,会有人选择阿宓吗?");
Console.WriteLine(" 沦陷在爱情的泡影中。");
Console.WriteLine(" 明明说好的,要永远在一起。");
Console.WriteLine(" 果然,先爱上的那个人,是输家。");
Console.WriteLine(" 获得皮肤-经典");
}
}
⑤上端调用
Console.WriteLine(" 装饰器模式");
Console.WriteLine(" *********************");
AbstractBaseCharacter zhenji = new ZhenjiPlay()
{
Id = 1,
Name = "颖宝"
};
zhenji = new ZhenJiWith_冰雪圆舞曲(zhenji);
zhenji = new ZhenJiWith_花好人间(zhenji);
zhenji = new ZhenJiWith_幽恒(zhenji);
zhenji = new ZhenJiWith_游园惊梦(zhenji);
zhenji.Show();
zhenji.Play();
Console.WriteLine($" 当前时间{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
分析:从上端调用的地方可以看出,实际上每次进行调用都是使用的基类因此可以不停的嵌套,并且可以随意调整顺序。
4:装饰器模式的优缺点
1:优点
动态扩展灵活:对于扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加。通过选择不同的具体装饰类,可以动态扩展对象的行为
多次装饰:可以对一个对象进行多次装饰,使用不同的具体装饰类以及这些装饰类的排列组合,可以创造很多不同行为的组合
构件与装饰类独立变化:具体构件类以及具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类或者具体装饰类,无须修改原有代码,符合开闭原则
2:缺点
对象较多:使用装饰模式会产生很多小对象,这些对象的区别在于相互连接方式的不同,小对象过多会一定程度上影响性能
排查繁琐:尽管装饰模式比继承更加灵活,但也意味着比继承更加容易出错,排错也很困难,对于多次装饰后的对象可能需要逐级排查
5:适用场景
在不影响其他对象的情况下,以动态和透明的方式给单个对象增加职责。
在不能采用继承扩展系统或者采用继承不利于对系统扩展和维护时可以使用装饰模式。
如果想要动态的给一个类增加功能,并且这个功能还希望可以动态的撤销。
6:相关扩展
1:运行结果
2:甄姬皮肤
1:冰雪圆舞曲
2:花好人间
3:幽恒
4:游园惊梦
3:甄姬手办
1:原型版
2:Q版
4:甄姬的历史身份
5:王者前辈的指导
6:忠告
多读书,多看报,少打王者,多睡觉!
“果然,先爱上的那个人,是输家”,缘于王者,终于甄姬,卸载了,离开了。