设计模式(一)--策略模式(Strategy Pattern)

一、模式介绍

    策略模式属于对象的行为模式,定义了算法簇,不同类型的算法分别封装起来,让他们之间可以相互替换,此模式让算法的变化,独立于算法使用者。策略模式属于行为行模式 。

二、场景解说

    以一个简单的三国游戏为例,首先应该有人物,而人物具有不同的外貌以及移动行为。

   

    游戏基本人物出来了,现在是时候要开始战斗了,因此我们加上战斗的方法,不同人物擅长不同的兵器,因此需要重载不同的fight()方法。


    随着档次的提高,现在弄来了一匹马,作为大佬的刘备,就开始骑上马了。


如果这时候我们的卧龙骑马出山了,我们又该如何?


随着人物的不断增加,我们会发现角色的子类中重复的行为代码也越来越多,生活条件提高了,自然骑马的人将越来越多。此外我们也很难了解人物的全部行为,人物需要以什么方式移动,需要用什么方式战斗。而且一旦修改父类,子类可能也会受到很大的影响,比如如果修改了父类的移动行为骑马,这时候子类像张飞、关羽还是步行的人员就需要改变。

此时我们就应该思考如何解决这类问题。

首先,我们应该将变化的部分剥离出来,让他们不影响不变的部分。因此,将角色的move行为和fight行为提取出来。其次,我们需要面向接口编程,使模块依赖于抽象而不是实体。

最终版UML图


角色只提供一个关羽为例,其余角色实现类似直接继承Role即可。角色使用了抽象类,使用组合的方式持有Move和Fight行为的抽象接口,屏蔽具体实现方式,实际用户可以在构造方法上指定用户的行为或者调用Role类的对应的set方法实现动态改变行为。该设计模式即为策略模式。

三、场景演练JAVA实现

package com.sn.strategy.threekingdom;

public abstract class Role {
    protected FightBehivor fightBehivor;
    protected MoveBehavior moveBehavior;

    /**
     * 外形,也可以根据实际需要添加参数初始化不同造型
     */
    public abstract void display();

    /**
     * 调用移动行为
     */
    public void doMove(){
        moveBehavior.move();
    }

    /**
     * 调用战斗行为
     */
    public void  doFight(){
        fightBehivor.fight();
    }

    /**
     * 利用多态,运行时可以动态改变战斗行为
     * @param fightBehivor
     */
    public void setFightBehivor(FightBehivor fightBehivor) {
        this.fightBehivor = fightBehivor;
    }

    /**
     * 利用多态,运行时可以动态改变移动行为
     * @param moveBehavior
     */
    public void setMoveBehavior(MoveBehavior moveBehavior) {
        this.moveBehavior = moveBehavior;
    }
}

package com.sn.strategy.threekingdom;

/**
 * 战斗行为
 */
public interface FightBehivor {
    /**
     * 战斗
     */
    void fight();
}

package com.sn.strategy.threekingdom;

/**
 * 移动行为
 *
 */
public interface MoveBehavior {
    /**
     * 移动
     */
    void move();
}

package com.sn.strategy.threekingdom.impl;

import com.sn.strategy.threekingdom.FightBehivor;

public class FightWithLance implements FightBehivor {
    @Override
    public void fight() {
        System.out.println("战斗:矛");
    }
}

package com.sn.strategy.threekingdom.impl;

import com.sn.strategy.threekingdom.FightBehivor;

public class FightWithWorse implements FightBehivor {
    @Override
    public void fight() {
        System.out.println("战斗:剑");
    }
}

package com.sn.strategy.threekingdom.impl;

import com.sn.strategy.threekingdom.FightBehivor;
import com.sn.strategy.threekingdom.MoveBehavior;
import com.sn.strategy.threekingdom.Role;

/**
 * 角色:关羽
 */
public class GuanYu extends Role {

    public GuanYu(FightBehivor fightBehivor, MoveBehavior moveBehavior) {
        //父类定义,创建角色时就可以传入对应行为
        this.fightBehivor=fightBehivor;
        this.moveBehavior=moveBehavior;
    }

    @Override
    public void display() {
        System.out.println("正义荣耀装");
    }
}

package com.sn.strategy.threekingdom.impl;

import com.sn.strategy.threekingdom.FightBehivor;
import com.sn.strategy.threekingdom.MoveBehavior;
import com.sn.strategy.threekingdom.Role;

/**
 * 角色:刘备
 */
public class LiuBei extends Role {


    public LiuBei(FightBehivor fightBehivor, MoveBehavior moveBehavior) {
        //父类定义,创建角色时就可以传入对应行为
        this.fightBehivor=fightBehivor;
        this.moveBehavior=moveBehavior;
    }

    @Override
    public void display() {
        System.out.println("王者装");
    }
}

package com.sn.strategy.threekingdom.impl;

import com.sn.strategy.threekingdom.MoveBehavior;

public class RideHorse implements MoveBehavior{
    @Override
    public void move() {
        System.out.println("移动:骑马");
    }
}

package com.sn.strategy.threekingdom.impl;

import com.sn.strategy.threekingdom.MoveBehavior;

public class Walk implements MoveBehavior {
    @Override
    public void move() {
        System.out.println("移动:走");
    }
}

package com.sn.strategy.threekingdom.impl;

import com.sn.strategy.threekingdom.FightBehivor;
import com.sn.strategy.threekingdom.MoveBehavior;
import com.sn.strategy.threekingdom.Role;

/**
 * 角色:关羽
 */
public class ZhanFei extends Role {

    public ZhanFei(FightBehivor fightBehivor, MoveBehavior moveBehavior) {
        //父类定义,创建角色时就可以传入对应行为
        this.fightBehivor=fightBehivor;
        this.moveBehavior=moveBehavior;
    }

    @Override
    public void display() {
        System.out.println("霸气侧漏装");
    }
}
测试类

package com.sn.strategy.threekingdom.test;

import com.sn.strategy.threekingdom.Role;
import com.sn.strategy.threekingdom.impl.*;

public class StrategyTest {
    public static void main(String[] args) {
        System.out.println("生成一个角色:刘备");
        Role role = new LiuBei(new FightWithWorse(),new RideHorse());
        role.display();
        role.doMove();
        role.doFight();
        System.out.println("刘备:我骑马骑累了,要走路");
        role.setMoveBehavior(new Walk());
        role.doMove();
        System.out.println("刘备:用剑没意思,给我来支矛");
        role.setFightBehivor(new FightWithLance());
        role.doFight();
    }
}
输出结果

生成一个角色:刘备
王者装
移动:骑马
战斗:剑
刘备:我骑马骑累了,要走路
移动:走
刘备:用剑没意思,给我来支矛
战斗:矛


四、总结

1.结构

  • 定义抽象的用户(环境对象),以组合的方式持有策略,持有抽象策略的对象(Role)
  • 定义抽象的策略,这样降低了用户对实际策略行为的依赖,仅依赖于策略接口
  • 定义实际用户,实现抽象用户类
  • 定义实际策略,实现抽象策略类

2.设计原则

  • 面向接口编程,而不是面向实现编程,接口包括抽象类
  • 封装变化:找出应用中变化的部分,将其独立出来,与不变的部分分离
  • 多用组合,少用继承(降低耦合度)

3.优点

  • 提高扩展性:策略的扩展更加容易,只需增加新的策略实现类
  • 降低耦合度:是有组合的方式持有抽象对象,使用者不需要了解实际策略的实现,只是需要了解有哪些策略即可,不需要依赖于具体策略
  • 动态改变策略

4.缺点

  • 类数目增加了,每种策略都有自己的实现。

参考资料:《Head First 设计模式》《常用设计模式在软件开发中的应用》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值