《设计模式与游戏完美开发》——第六周读书笔记

在上一周的读书笔记中我介绍了中介者模式,本周的读书笔记来介绍一下桥接模式。
前言
现在流行的游戏都是有武器的。一个游戏不可能让玩家从头打到尾都是一把‘’小手枪‘’。例如,现在特别火的《贪婪洞窟2》和《元气骑士》,其非常核心的一大玩法就是武器系统,里面有多种多样的武器,每把武器都有属于自己的炫酷外观和特效,让玩家非常容易激起收藏欲。而事实正是如此,大部分网游,玩家要么买装备,要么买时装。而在本书中提供的案例中也是有武器系统的。每一款游戏都至少有一个可操控角色,每一个玩家都可以装备适合自己的武器,武器有一些是通用的,有一些武器是某些特定角色可以装备的,而这样就会出现组合的问题了。
常规的解决方案
假设现在有A,B,C三种通用武器,角色是分两个类型,一个是敌方阵营,一个是玩家阵营。
把3种不同的武器声明为一个枚举类型,然后写一个武器接口,同时写一个角色抽象接口内部一个武器成员变量,一个攻击的通用方法。然后让Enemy和Solider分别继承自这个角色抽象接口,利用一个switch判断枚举类型是哪种武器,然后执行相应的操作。
诚然,这种解决方案非常省事,按照这种方式写好后其实就成了一个交叉组合编程,每一个角色里面把三种武器的相应的攻击效果全部都存放在了自己的类内部,那么如果策划一改游戏需求呢,如果想要修改一把武器的属性,那么所有的角色里面使用这一把武器的那一部分必须要修改,如果是3个角色就要改3处,而如果是要增加某一个新角色,乖乖,里面所有的武器都必须给添加进去,如果是20把武器呢,甚至于30把呢,想想就令人头皮发麻。这个时候就需要请出我们的正主——桥接模式
桥接模式
本模式在GOF中的解释是:“将抽象与实现分离,使二者可以独立地变化”。
很多人可能就认为这是“只依赖接口而不依赖实现”原则的另外一个表现吗?那好我们来看下面这个例子。
假设:我们要实现一个“3D绘画工具”,并且要支持当前最常见的OpenGL和DirectX两个引擎。
那么把形状抽象,然后不同形状的物体继承自这个父类,而这些继承的子类也作为抽象类,具体再分别用两个引擎去继承具体的形状类,就会形成如下的图。
在这里插入图片描述
这样一来确实看似是依赖了抽象,因为在外面调用Draw方法时候,只需要调用ISpere里面的Darw方法,但我们的问题是是不是就解决了呢,现在就需要增加一个正方形的绘图的东西那么,从图中可以明确的看出,会增加一个抽象接口,2个具体实现类。那么是不是说我们的依赖抽象而不依赖实现这个原则就错误了吗。不,并不是,关键是在于两个问题的核心点都不一样,这个原则是为了解决在外面调用这个系统时候,如果直接这个系统的功能变更了,在外部调用的所有类都必须要更改,而只加了接口后,只需要这个系统的内部增加一个就行,而目前我们这个关注的这个问题,不管是引擎绘图,还是角色与武器的组合问题,问题都出现在了内部,这两个系统组合起来一起为外部工作是没问题,但是内部我们也要尽可能 的降低耦合,这才是这个问题的本质。
同样那么我们就可以再一次进行抽象,就把其中另外一个系统又进行抽象,提取一个抽象接口,这样从最上层,到最下层,都不会产生依赖实现了。那么就会出现如下图的情况:
在这里插入图片描述
这样一看是不是舒服多了呢,不管是从哪一层进去更改,都只会在本层进行修改,而不会影响到其他层。而单独来看这两个系统的结构是不是非常像是一座桥呢,这就是桥接模式了,代码如下:

using System;
/// <summary>
/// 桥接模式
/// </summary>
namespace ConsoleApp59
{
    public abstract class RenderEngine
    {
        public abstract void Render(string objname);
    }
    public class DirectX : RenderEngine
    {
        public override void Render(string objname)
        {
            DxRender(objname);
        }
        public void DxRender(string objname)
        {
            Console.WriteLine("DxRender:" + objname);
        }
    }
    public class OpenGL : RenderEngine
    {
        public override void Render(string objname)
        {
            OpenGLRender(objname);
        }
        public void OpenGLRender(string objname)
        {
            Console.WriteLine("OpenGLRender:" + objname);
        }
    }
    public abstract class Ishape
    {
        protected RenderEngine m_renderEngine = null;
        public void SetRenderEngine(RenderEngine renderEngine)
        {
            m_renderEngine = renderEngine;
        }
        public abstract void Draw();
    }
    public class Sphere : Ishape
    {
        public override void Draw()
        {
            m_renderEngine.Render("Sphere");
        }
    }
    public class Cylinder : Ishape
    {
        public override void Draw()
        {
            m_renderEngine.Render("Cylinder");
        }
    }

    public class Cube : Ishape
    {
        public override void Draw()
        {
            m_renderEngine.Render("Cube");
        }
    }


    public
    class Program
    {
        static void Main(string[] args)
        {
            Sphere sphere = new Sphere();
            Cube cube = new Cube();
            DirectX directX = new DirectX();
            OpenGL openGL = new OpenGL();
            //选择哪个引擎渲染
            sphere.SetRenderEngine(directX);
            cube.SetRenderEngine(openGL);
            sphere.Draw();
            cube.Draw();
            Console.ReadKey();
        }
    }
}

而武器系统也可以类似于这样进行设计,在此就不予赘述(留点思考)。
至此,以上就是本周的读书笔记。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风萧水寒人往前

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值