使用建造者模式模拟游戏地图的创建

使用建造者模式模拟游戏地图的创建

换种形式学设计模式,让自己更有兴趣的学设计模式 :)

本文使用了建造者模式创建不同的游戏地图,当然是用控制台模拟的假地图...

1 何为建造者模式

1.1 介绍

建造者模式,是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。

1.2 特点

  • 隔离复杂对象的创建和使用,相同的方法,不同执行顺序,产生不同事件结果
  • 多个部件都可以装配到一个对象中,但产生的运行结果不相同
  • 产品类非常复杂或者产品类因为调用顺序不同而产生不同作用
  • 初始化一个对象时,参数过多,或者很多参数具有默认值
  • Builder模式不适合创建差异性很大的产品类
    产品内部变化复杂,会导致需要定义很多具体建造者类实现变化,增加项目中类的数量,增加系统的理解难度和运行成本
  • 需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;

总的来说,建造者模式就是把一个个零部件添加到了一样产品上,最后创建出一个完整的产品,不同产品之间需要有共性,例如汽车都有轮子和引擎,可能引擎马力不同,轮子数量不同,用户只需要挑选成品产品而不需要知道造车子的细节。

2 建造者模式框架

2.1 建造者模式UML图

UML图

2.2 包含角色

  • 指挥者(Director)直接和客户(Client)进行需求沟通;
  • 沟通后指挥者将客户创建产品的需求划分为各个部件的建造请求(Builder);
  • 将各个部件的建造请求委派到具体的建造者(ConcreteBuilder);
  • 各个具体建造者负责进行产品部件的构建;
  • 最终构建成具体产品(Product)。

3 创建游戏地图

3.1 需求分析

用户通过客户端选择地图种类之后,系统自动为用户创建不同的游戏地图。

游戏地图包含两种:

  • 森林地图(树多)
  • 怪兽地图(怪兽多)

地图包含的共通元素有:

  • 怪兽
  • NPC

3.2 确定模式

通过分析可知:

  1. 最终产品 游戏地图 差异性不大,包含共通性。
  2. 最终产品包含多种元素,有一定的复杂性。
  3. 地图元素的不同决定了地图的差异性,

通过以上的项目特点,我们可以看到建造者模式很符合本项目需求。?

3.3 代码编写

3.3.1 项目结构图

项目图
项目UML图

3.3.2 产品零配件代码

此项目中的产品零件即为地图元素

地图元素抽象类:

    /// <summary>
    /// 地图元素抽象类
    /// </summary>
    abstract class MapElement
    {
        //x坐标
        public int _x;
        //y坐标
        public int _y;
        public string _name;
        public MapElement(string name)
        {
            //模拟加载地图元素耗时,并且需要一定间隔让随机数产生不重复
            Thread.Sleep(100);
            Random random = new Random();
            this._x = random.Next(0, 100);
            this._y = random.Next(0, 100);
            this._name = name;

        }
        //元素展示
        public abstract void Dispaly();
    }

具体地图元素类:包含怪兽、NPC、树、路

/// <summary>
/// 怪兽类
/// </summary>
class Monster : MapElement
{
    public double _blood;
    public Monster(string name) : base(name)
    {
        this._blood =new Random().Next(0,100);
    }
    public override void Dispaly()
    {
        Console.WriteLine($"元素类型:怪兽;血量:{_blood};元素名称:{_name};元素坐标x:{_x},y:{_y};\r\n");
    }
}
    /// <summary>
    /// NPC类
    /// </summary>
    class NPC : MapElement
    {
        public string _job;
        public NPC(string name, string job) : base(name)
        {
            this._job = job;
        }
        public override void Dispaly()
        {
            Console.WriteLine($"元素类型:NPC;职位:{_job};元素名称:{_name};元素坐标x:{_x},y:{_y};\r\n");
        }
    }
/// <summary>
/// 树类
/// </summary>
class Tree : MapElement
{
    public int _height;
    public Tree(string name) : base(name)
    {
        this._height = new Random().Next(1,50);
    }

    public override void Dispaly()
    {
        Console.WriteLine($"元素类型:树;高度:{_height}m;元素名称:{_name};元素坐标x:{_x},y:{_y};\r\n");
    }
}
/// <summary>
/// 路
/// </summary>
class Way : MapElement
{
    public int _length;
    public Way(string name) : base(name)
    {
        this._length = new Random().Next(100,10000);
    }

    public override void Dispaly()
    {
        Console.WriteLine($"元素类型:路;长度:{_length}m;元素名称:{_name};元素坐标x:{_x},y:{_y};\r\n");
    }
}

这些地图元素是地图的"零配件",地图元素的不同导致地图种类的不同。

3.3.3 具体产品

此项目中具体的产品即为地图(Game Map)

游戏地图类:

/// <summary>
/// 游戏场景(具体的产品)
/// </summary>
class GameMap
{
    //地图元素集合
    public IList<MapElement> MapElements = new List<MapElement>();
    /// <summary>
    /// 添加地图元素
    /// </summary>
    /// <param name="MapElement"></param>
    public void AddMapElements(MapElement mapElement)
    {
        MapElements.Add(mapElement);
    }
    /// <summary>
    /// 展示地图
    /// </summary>
    public void Show()
    {
        Console.WriteLine("——————————————————————地图显示————————————————————\r\n");
        foreach (var element in MapElements)
        {
            element.Dispaly();
        }
    }
}
3.3.4 创建者接口

创建者接口为创建一个Product对象的各个部位指定抽象接口。

interface IGameMapBuilder
{
    void BuilderTree();
    void BuilderWay();
    void BuilderMonster();
    void BuilderNPC();
    GameMap GetGameMap();
}
3.3.5 具体创建者

具体创建者是产品构建差异体现,具体实现如何构建产品。

本项目中的具体创建者有两个:

  • ForestMapBuilder(森林地图创建者)
  • MonsterMapBuilder(怪兽地图创建者)

这两个创建者都继承抽象创建者IGameMapBuilder

ForestMapBuilder:

/// <summary>
/// 森林游戏场景具体建造者----特点:树多 
/// </summary>
class ForestMapBuilder : IGameMapBuilder
{
    private GameMap gameMap = new GameMap();
    public void BuilderMonster()
    {
        Monster monster1 = new Monster("哥斯拉");
        Monster monster2 = new Monster("异形");
        Monster monster3 = new Monster("女朋友");
        gameMap.AddMapElements(monster1);
        gameMap.AddMapElements(monster2);
        gameMap.AddMapElements(monster3);
    }
    public void BuilderNPC()
    {
        NPC npc1 = new NPC("NPC", "任务接取处");
        gameMap.AddMapElements(npc1);
    }
    public void BuilderTree()
    {
        for (int i = 0; i < 15; i++)
        {
            gameMap.AddMapElements(new Tree($"树{i}"));
        }
    }
    public void BuilderWay()
    {
        Way way = new Way("主路");
        gameMap.AddMapElements(way);
    }
    public GameMap GetGameMap()
    {
        return gameMap;
    }
}

MonsterMapBuilder:

/// <summary>
/// 怪物地图创建者 特点:怪物多
/// </summary>
class MonsterMapBuilder : IGameMapBuilder
{
    private GameMap gameMap = new GameMap();
    public void BuilderMonster()
    {
        for (int i = 0; i < 15; i++)
        {
            gameMap.AddMapElements(new Monster($"怪物{i}"));
        }
    }
    public void BuilderNPC()
    {
        NPC npc1 = new NPC("任务npc", "任务接取处");
        NPC npc2 = new NPC("商店npc", "购买物品");
        gameMap.AddMapElements(npc1);
        gameMap.AddMapElements(npc2);
    }
    public void BuilderTree()
    {
        for (int i = 0; i < 3; i++)
        {
            gameMap.AddMapElements(new Tree($"树{i}"));
        }
    }
    public void BuilderWay()
    {
        Way way1 = new Way("主路");
        Way way2 = new Way("史诗之路");
        gameMap.AddMapElements(way1);
        gameMap.AddMapElements(way2);
    }
    public GameMap GetGameMap()
    {
        return gameMap;
    }
}
3.3.6 指挥者

指挥者指定创建者创建,并且决定创建顺序

本项目中的创建者为GameMapDirect

class GameMapDirector
{
    public void Construct(IGameMapBuilder builder)
    {
        Console.WriteLine("---------------正在加载树资源-----------------");
        builder.BuilderTree();
        Console.WriteLine("---------------正在加载怪物资源---------------");
        builder.BuilderMonster();
        Console.WriteLine("---------------正在加载道路资源---------------");
        builder.BuilderWay();
        Console.WriteLine("---------------正在加载NPC资源----------------");
        builder.BuilderNPC();
        Console.WriteLine("-----------------资源加载完毕-----------------");
    }
}

Construct()方法参数为创建者,方法内部指定了创建顺序。

3.3.7 客户端代码
    static void Main(string[] args)
    {
        Console.WriteLine("请选择地图类型:1.怪兽地图 2.森林地图");
        string result = Console.ReadLine().Trim();
        IGameMapBuilder builder = null;
        if (Convert.ToInt32(result) == 1)
        {
            Console.WriteLine("--------------正在加载怪兽地图--------------------");
            builder = new MonsterMapBuilder();
        }
        else
        {
            Console.WriteLine("--------------正在加载森林地图--------------------");
            builder = new ForestMapBuilder();
        }
        GameMapDirector director = new GameMapDirector();

        //建造者指派builder去建造地图
        director.Construct(builder);
        //建造者建造好地图之后返回地图
        GameMap gameMap = builder.GetGameMap();
        //地图呈现
        gameMap.Show();
        Console.Read();
    }
3.3.8 最终结果

结果

可以看到,玩家选择了怪兽地图,指挥者指定怪兽地图建造者建造地图,建造顺序按照指挥者方法内部顺序加载地图,最后呈现了一个怪物很多的地图:)

4 总结

4.1 优缺点:

优点:

  • 使用建造者模式可以使客户端不必知道产品内部组成的细节。
  • 具体的建造者类之间是相互独立的,这有利于系统的扩展。
  • 具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。

缺点:

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

4.2 和抽象工厂对比

  • 抽象工厂返回一个一系列相关产品族,建造者返回一个组装好的完整产品。
  • 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象 。
  • 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车

​ 看到第三点突然想到,本项目中的地图元素可以使用简单工厂实现或者工厂方法模式实现,简单工厂的话就用Switch xxxxx,使用工厂方法模式的话就有TreeFactoryMonsterFactory....

​ 如果再之后怪兽细分为各种怪兽:皮卡丘、小拉达、等等等...那么就可以用抽象工厂模式生产怪兽族。。。妙呀?


版权声明:本文为吴恺的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文地址:https://www.cnblogs.com/zaijianba/p/11584625.html

我的个人博客地址:www.wukailiving.cn

本文是个小菜鸡写的,对代码理解并不深刻,轻喷。

如有不足之处,欢迎指正!

转载于:https://www.cnblogs.com/zaijianba/p/11584625.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值