java 设计模式之桥接模式,策略模式
1.引出设计模式
相信大家都玩过王者荣耀这款游戏。我们知道现在大概有五十多个英雄且各自技能及背景故事被动都不一样而且还带着召唤师技能比如实现,惩戒,弱化等。每一个英雄其实就算是一个策略,实现抽象类‘英雄’,并且每个英雄互不干扰。对于召唤师技能又可以和英雄组合进入游戏里操作使用。那让我们来看看一个匹配模式的简略流程来感受设计模式。
2. 策略模式
2.1 策略模式的定义与特点
策略(Strategy)模式
的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
策略模式的主要优点如下。
1.多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if…else 语句、switch…case 语句。
2.策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
3.策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
4.策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
5.策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
其主要缺点如下。
1.客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
2.策略模式造成很多的策略类,增加维护难度。
2.2 策略模式的结构与实现
策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面,作为一个抽象策略类的子类。策略模式的重心不是如何实现算法,而是如何组织这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性,现在我们来分析其基本结构和实现方法。
1.模式的结构
策略模式的主要角色如下。
1.抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
2.具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
3.环境(Context)类:持有一个策略类的引用,最终给客户端调用。
2.实现
英雄抽象类:
@Data
public abstract class Hero {
//英雄名字
private String heroName;
//英雄描述
private String heroDescription;
//英雄普攻
public abstract void normalAttack();
//英雄被动
public abstract void passiveSkill();
}
后裔的实现类:
public class HouYi extends Hero{
@Override
public void normalAttack() {
System.out.println("qiuqiuqiu~");
}
@Override
public void passiveSkill() {
System.out.println("箭会增多");
}
public HouYi() {
super.setHeroName("后裔");
super.setHeroDescription("觉醒吧,猎杀时刻");
}
public void firstSkill()
{
System.out.println("强化");
}
public void secondSkill()
{
System.out.println("减速");
}
public void thirdSkill()
{
System.out.println("大鸟");
}
}
吉吉国王实现类:
public class MonkeyJi extends Hero {
@Override
public void normalAttack() {
System.out.println("pong~pong~");
}
@Override
public void passiveSkill() {
System.out.println("先天20%暴击率");
}
public MonkeyJi() {
super.setHeroName("吉吉");
super.setHeroDescription("取经之路就在脚下");
}
public void firstSkill() {
System.out.println("护盾");
}
public void secondSkill() {
System.out.println("位移");
}
public void thirdSkill() {
System.out.println("大棒");
}
}
目前为止只做了两个英雄,这种设计模式有什么好处呢,好处就是新增英雄很方便,削弱增强很方便,重做也是彼此独立。我觉得可以通过枚举创建实例。
3. 桥接模式
3.1 桥接模式的定义与特点
桥接(Bridge)模式
的定义如下:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
通过上面的讲解,我们能很好的感觉到桥接模式遵循了里氏替换原则和依赖倒置原则,最终实现了开闭原则,对修改关闭,对扩展开放。这里将桥接模式的优缺点总结如下。
桥接(Bridge)模式的优点是:
1.抽象与实现分离,扩展能力强
2.符合开闭原则
3.符合合成复用原则
4.其实现细节对客户透明
缺点是:由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,能正确地识别出系统中两个独立变化的维度,这增加了系统的理解与设计难度。
3.2 桥接模式的结构与实现
可以将抽象化部分与实现化部分分开,取消二者的继承关系,改用组合关系。
1. 模式的结构
1.桥接(Bridge)模式包含以下主要角色。
2.抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
3.扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
4.实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
5.具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
2. 实现
召唤师技能:
public interface SummonerSkills {
public void useTheSkill();
}
闪现的实现类:
public class ShanXian implements SummonerSkills {
@Override
public void useTheSkill() {
System.out.println("位移一段距离");
}
}
净化的实现类:
public class JingHua implements SummonerSkills {
@Override
public void useTheSkill() {
System.out.println("解控加免控");
}
}
修改英雄抽象类:
import lombok.Data;
@Data
public abstract class Hero {
//英雄名字
private String heroName;
//英雄描述
private String heroDescription;
//召唤师技能
private SummonerSkills summonerSkills;
//英雄普攻
public abstract void normalAttack();
//英雄被动
public abstract void passiveSkill();
public void useSkill()
{
this.summonerSkills.useTheSkill();
}
}
加入了召唤技能的引用属于组合关系
4.测试
public class Test {
public static void main(String[] args) {
//选英雄
Hero hero =new MonkeyJi();
//台词
System.out.println("英雄:"+hero.getHeroName()+ "\n台词:"+hero.getHeroDescription());
//选择召唤师技能
hero.setSummonerSkills(new ShanXian());
//开始游戏
System.out.println("全军出击!");
//使用吉吉二技能
MonkeyJi monkeyJi =(MonkeyJi) hero;
monkeyJi.secondSkill();
//吉吉大招
monkeyJi.thirdSkill();
//吉吉闪现
hero.useSkill();
}
}
运行结果:
英雄:吉吉
台词:取经之路就在脚下
全军出击!
位移
大棒
位移一段距离
现在整个桥接,策略模式就结束了。
可能有人会问了,如何设计成通用的测试,就是说模仿前端传值。我只告诉后台我选择了吉吉国王或者凯等英雄,自己去建立对象
我觉得可以通过枚举完成,根据名字创建对象再或者通过代理完成。