zoukankan      html  css  js  c++  java
  • 设计模式 策略模式 以角色游戏为背景

    今天不想写代码,给大家带来一篇设计模式的文章,帮助大家能够把系统组织成easy了解、easy维护、具有弹性的架构。

    先来看看策略模式的定义:

    策略模式(Strategy Pattern):定义了算法族,分别封装起来,让它们之间可相互替换,此模式让算法的变化独立于使用算法的客户。

    好了。对于定义。肯定不是一眼就能看明确的,不然这篇文章就收尾了,对于定于大家简单扫一眼。知道个大概,然后继续读以下的文章,读完以后再来回味。效果嘎嘣脆。大家应该都玩过武侠角色游戏,以下我就以角色游戏为背景,为大家介绍:如果公司须要做一款武侠游戏。我们就是负责游戏的角色模块,需求是这种:每一个角色相应一个名字,每类角色相应一种样子,每一个角色拥有一个逃跑、攻击、防御的技能。

    初步的代码:

    package com.zhy.bean;
    
    /**
     * 游戏的角色超类
     * 
     * @author zhy
     * 
     */
    public abstract class Role
    {
    	protected String name;
    
    	protected abstract void display();
    
    	protected abstract void run();
    
    	protected abstract void attack();
    
    	protected abstract void defend();
    
    }
    
    package com.zhy.bean;
    
    public class RoleA extends Role
    {
    	public RoleA(String name)
    	{
    		this.name = name;
    	}
    
    	@Override
    	protected void display()
    	{
    		System.out.println("样子1");
    	}
    
    	@Override
    	protected void run()
    	{
    		System.out.println("金蝉脱壳");
    	}
    
    	@Override
    	protected void attack()
    	{
    		System.out.println("降龙十八掌");
    	}
    
    	@Override
    	protected void defend()
    	{
    		System.out.println("铁头功");
    	}
    
    }
    

    没几分钟。你写好了上面的代码,认为已经充分发挥了OO的思想,正在窃喜,这时候项目经理说。再加入两个角色

    RoleB(样子2 ,降龙十八掌,铁布衫,金蝉脱壳)。

    RoleC(样子1,拥有九阳神功,铁布衫。烟雾弹)。

    于是你认为没问题,開始写代码,继续集成Role,写成以下的代码:

    package com.zhy.bean;
    
    public class RoleB extends Role
    {
    	public RoleB(String name)
    	{
    		this.name = name;
    	}
    
    	@Override
    	protected void display()
    	{
    		System.out.println("样子2");
    	}
    
    	@Override
    	protected void run()
    	{
    		System.out.println("金蝉脱壳");//从RoleA中拷贝
    	}
    
    	@Override
    	protected void attack()
    	{
    		System.out.println("降龙十八掌");//从RoleA中拷贝
    	}
    
    	@Override
    	protected void defend()
    	{
    		System.out.println("铁布衫");
    	}
    
    }
    

    package com.zhy.bean;
    
    public class RoleC extends Role
    {
    	public RoleC(String name)
    	{
    		this.name = name;
    	}
    
    	@Override
    	protected void display()
    	{
    		System.out.println("样子1");//从RoleA中拷贝
    	}
    
    	@Override
    	protected void run()
    	{
    		System.out.println("烟雾弹");
    	}
    
    	@Override
    	protected void attack()
    	{
    		System.out.println("九阳神功");
    	}
    
    	@Override
    	protected void defend()
    	{
    		System.out.println("铁布衫");//从B中拷贝
    	}
    
    }
    

    写完之后,你自己似乎没有当初那么自信了,你发现代码中已经存在相当多反复的代码。须要考虑又一次设计架构了。于是你想,要不把每一个技能都写成接口,有什么技能的角色实现什么接口。简单一想,认为这想法高大尚啊,可是实现起来会发现,接口并不能实现代码的复用,每一个实现接口的类,还是必须写自己写实现。于是。we need change ! 遵循设计的原则,找出应用中可能须要变化的部分,把它们独立出来,不要和那些不须要变化的代码混在一起。我们发现,对于每一个角色的display,attack,defend,run都是有可能变化的。于是我们必须把这写独立出来。

    再依据还有一个设计原则:针对接口(超类型)编程,而不是针对实现编程。于是我们把代码改造成这样:

    package com.zhy.bean;
    
    public interface IAttackBehavior
    {
    	void attack();
    }
    

    package com.zhy.bean;
    
    public interface IDefendBehavior
    {
    	void defend();
    }
    

    package com.zhy.bean;
    
    public interface IDisplayBehavior
    {
    	void display();
    }
    

    package com.zhy.bean;
    
    public class AttackJY implements IAttackBehavior
    {
    
    	@Override
    	public void attack()
    	{
    		System.out.println("九阳神功!

    "); } }

    package com.zhy.bean;
    
    public class DefendTBS implements IDefendBehavior
    {
    
    	@Override
    	public void defend()
    	{
    		System.out.println("铁布衫");
    	}
    
    }
    

    package com.zhy.bean;
    
    public class RunJCTQ implements IRunBehavior
    {
    
    	@Override
    	public void run()
    	{
    		System.out.println("金蝉脱壳");
    	}
    
    }
    

    这时候须要对Role的代码做出改变:

    package com.zhy.bean;
    
    /**
     * 游戏的角色超类
     * 
     * @author zhy
     * 
     */
    public abstract class Role
    {
    	protected String name;
    
    	protected IDefendBehavior defendBehavior;
    	protected IDisplayBehavior displayBehavior;
    	protected IRunBehavior runBehavior;
    	protected IAttackBehavior attackBehavior;
    
    	public Role setDefendBehavior(IDefendBehavior defendBehavior)
    	{
    		this.defendBehavior = defendBehavior;
    		return this;
    	}
    
    	public Role setDisplayBehavior(IDisplayBehavior displayBehavior)
    	{
    		this.displayBehavior = displayBehavior;
    		return this;
    	}
    
    	public Role setRunBehavior(IRunBehavior runBehavior)
    	{
    		this.runBehavior = runBehavior;
    		return this;
    	}
    
    	public Role setAttackBehavior(IAttackBehavior attackBehavior)
    	{
    		this.attackBehavior = attackBehavior;
    		return this;
    	}
    
    	protected void display()
    	{
    		displayBehavior.display();
    	}
    
    	protected void run()
    	{
    		runBehavior.run();
    	}
    
    	protected void attack()
    	{
    		attackBehavior.attack();
    	}
    
    	protected void defend()
    	{
    		defendBehavior.defend();
    	}
    
    }
    

    每一个角色如今仅仅须要一个name了:

    package com.zhy.bean;
    
    public class RoleA extends Role
    {
    	public RoleA(String name)
    	{
    		this.name = name;
    	}
    
    }
    

    如今我们须要一个金蝉脱壳。降龙十八掌。。铁布衫,样子1的角色A仅仅须要这样:

    package com.zhy.bean;
    
    public class Test
    {
    	public static void main(String[] args)
    	{
    
    		Role roleA = new RoleA("A");
    
    		roleA.setAttackBehavior(new AttackXL())//
    				.setDefendBehavior(new DefendTBS())//
    				.setDisplayBehavior(new DisplayA())//
    				.setRunBehavior(new RunJCTQ());
    		System.out.println(roleA.name + ":");
    		roleA.run();
    		roleA.attack();
    		roleA.defend();
    		roleA.display();
    	}
    }
    

    经过我们的改动,如今全部的技能的实现做到了100%的复用。而且随便项目经理须要什么样的角色,对于我们来说仅仅须要动态设置一下技能和展示方式,是不是非常完美。恭喜你,如今你已经学会了策略模式。如今我们回到定义,定义上的算法族:事实上就是上述样例的技能;定义上的客户:事实上就是RoleA,RoleB...;我们已经定义了一个算法族(各种技能),且依据需求能够进行相互替换。算法(各种技能)的实现独立于客户(角色)。如今是不是非常好理解策略模式的定义了。

    附上一张UML图。方便大家理解:


    最后总结一下OO的原则:

    1、封装变化(把可能变化的代码封装起来)

    2、多用组合,少用继承(我们使用组合的方式。为客户设置了算法)

    3、针对接口编程,不针对实现(对于Role类的设计全然的针对角色。和技能的实现没有关系)



    点击此处下载源代码







  • 相关阅读:
    LeetCode偶尔一题 —— 617. 合并二叉树
    《剑指offer》 —— 链表中倒数第k个节点
    《剑指offer》 —— 青蛙跳台阶问题
    《剑指offer》—— 二维数组中的查找
    《剑指offer》—— 替换空格
    《剑指offer》—— 合并两个排序的链表
    《剑指offer》—— 礼物的最大价值
    生成Nuget 源代码包来重用你的Asp.net MVC代码
    Pro ASP.Net Core MVC 6th 第四章
    Pro ASP.NET Core MVC 6th 第三章
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6898885.html
Copyright © 2011-2022 走看看