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类的设计全然的针对角色。和技能的实现没有关系)



    点击此处下载源代码







  • 相关阅读:
    vue中的具名插槽
    vue中默认插槽slot
    局部组件使用指令-方法-过滤器-计算属性
    vue创建局部组件
    Class Metaprogramming
    Attribute Descriptors
    Dynamic Attributes and Properties
    Concurrency with asyncio
    Concurrency with Futures
    Coroutines
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6898885.html
Copyright © 2011-2022 走看看