在之前的文章中我们讲了简单工厂模式,策略模式,单一职责原则,开放封闭原则,依赖倒转原则,装饰模式,代理模式,抽象工厂模式,上一节在抽象工程模式中讲了利用工厂模式创建英雄的过程,今天我将带大家用原型模式模拟一下魔兽世界里面的怪物创建,其实我平时很少玩游戏的,但是我喜欢对游戏进行分析,下面就讲一下设计思路:
我要模拟的是这样的场景,模拟游戏地图中的出怪功能:
地图中创建怪,也许一次不止要创建一个怪,而是创建一批怪,怎么编程才能让我们的游戏耗的资源小一点呢,对于大型的游戏,系统配置是玩游戏的瓶颈所在:
最易想到的就是用for循环去创建一批怪,但是这样每次创建一个怪,都要new一次,这样明显的是不太合理的。
下面我就讲一下如何用原型模式来解决这个问题;
原型模式其实就是将一个对象再创建到另外一个可定制的对象,而且不知道任何创建的细节。
在其它语言中如果想使用原型模式,必须要在要被克隆的类中定义Clone接口,然后在具体的类中去实现这个接口。
因为我用的.NET,在.net里面,Clone方法实现用是太多了,所以.NET在System下定义了ICloneable接口,其中就是唯一的一个方法,Clone,所以在使用的过程中我们只要实现Clone接口就可以了。
下面是我模拟的代码,贴出来和大家分享下:
/// <summary>
/// 怪物类
/// </summary>
abstract class Monster
{
/// <summary>
/// 怪物类构造函数
/// </summary>
/// <param name="name"></param>
public Monster(string name)
{
this.name = name;
}
private string name;
/// <summary>
/// 怪物名称
/// </summary>
public string Name
{
get { return name; }
set { name = value; }
}
/// <summary>
/// 怪物类型
/// </summary>
private string monsterType;
public string MonsterType
{
get { return monsterType; }
set { monsterType = value; }
}
/// <summary>
/// 怪物攻击力
/// </summary>
private int attack;
public int Attack
{
get { return attack; }
set { attack = value; }
}
private int defence;
/// <summary>
/// 怪物防御力
/// </summary>
public int Defence
{
get { return defence; }
set { defence = value; }
}
/// <summary>
/// 设置怪物的熟悉值
/// </summary>
public void SetProperty(string type,int attack,int defence)
{
this.monsterType = type;
this.attack = attack;
this.defence = defence;
}
public void SetSkill(string skillName,int defence,int attack)
{
skill.SkillName = skillName;
skill.Defence = defence;
skill.Attack = attack;
}
public Skill skill = new Skill();
/// <summary>
/// 显示技能属性值
/// </summary>
public void Display()
{
Console.WriteLine(string.Format("怪物名称:{0}\n怪物类型:{1};\n怪物攻击里:{2};\n怪物防御力:{3};\n怪物技能:{4};\n技能攻击力:{5};\n技能防御力:{6}\n------------------------------",this.Name,this.MonsterType,this.Attack,this.Defence,this.skill.SkillName,this.skill.Attack,this.skill.Defence));
}
public abstract Monster Clone();
public Monster(Skill skill)
{
this.skill = (Skill)skill.Clone();
}
}
细心的你也许发现我没有使用.NET提供的ICloneable接口,是的,这样是方便别的语言的朋友看,所以自己就写了,下面这个技能类就是我继承微软提供的,贴出代码
/// <summary>
/// 技能类
/// </summary>
class Skill:ICloneable
{
private string skillName;
/// <summary>
///技能名称
/// </summary>
public string SkillName
{
get { return skillName; }
set { skillName = value; }
}
private int attack;
/// <summary>
/// 技能攻击力
/// </summary>
public int Attack
{
get { return attack; }
set { attack = value; }
}
private int defence;
/// <summary>
/// 技能防御力
/// </summary>
public int Defence
{
get { return defence; }
set { defence = value; }
}
/// <summary>
/// 克隆新的技能
/// </summary>
/// <returns></returns>
public object Clone()
{
return (Skill)this.MemberwiseClone();
}
}
具体要创建的怪类,继承怪物类的总类
class DarkTroll:Monster
{
/// <summary>
/// 黑暗巨魔
/// </summary>
/// <param name="name"></param>
public DarkTroll(string name):base(name)
{
}
/// <summary>
/// 黑暗巨魔
/// </summary>
/// <param name="name"></param>
public DarkTroll(Skill skill0)
: base(skill0)
{
}
/// <summary>
/// 克隆怪物方法
/// </summary>
/// <returns></returns>
public override Monster Clone()
{
///创建当前对象的浅表副本,方法是创建一个新对象,然后将这个对象的非静态对象复制到新对象中,如果该字段是值类型,则对该字段进行逐一复制,
///如果是引用类型,则复制应用不复制引用对象,因此原始对象极其副本引用同一对象。
///
Monster obj = new DarkTroll(base.skill);
obj.Name = this.Name;
obj.MonsterType = this.MonsterType;
obj.Attack = this.Attack;
obj.Defence = this.Defence;
return obj;
}
}
在这里重点提心一下:MemberwiseClone()方法如果对象中的字段是值类型,就将该字段进行逐位复制,如果是引用类型,则是复制引用而不复制值。这样的话就会出现问题,如果由于游戏的需求,同一种怪物随机出两个不同的技能中的一种,如果用Clone()方法去实现的话,那么永远都只有一种技能,这个取决于最后一次引用中存放的值。
所以在复制的过程中出现了浅复制和深复制之分,浅复制只用于值类型,深复制就比较复杂一点,需要在需要变动的类中重新实现ICloneable接口,
/// <summary>
/// 克隆新的技能
/// </summary>
/// <returns></returns>
public object Clone()
{
return (Skill)this.MemberwiseClone();
}
以此来改变这一点,同时变换还有就是在引用类中必须重新改变Clone方法的写法:
/// <summary>
/// 克隆怪物方法
/// </summary>
/// <returns></returns>
public override Monster Clone()
{
///创建当前对象的浅表副本,方法是创建一个新对象,然后将这个对象的非静态对象复制到新对象中,如果该字段是值类型,则对该字段进行逐一复制,
///如果是引用类型,则复制应用不复制引用对象,因此原始对象极其副本引用同一对象。
///
Monster obj = new DarkTroll(base.skill);
obj.Name = this.Name;
obj.MonsterType = this.MonsterType;
obj.Attack = this.Attack;
obj.Defence = this.Defence;
return obj;
}
到此为止我们的原型模式就讲完了。
其实在我们日常编程中原型模式我们用的挺多了,比如说我们用的数据集对象DataSet,它就是一个Clone和一个Copy方法,Clone用来复制DataSet结构,但不复制DataSet数据,实现原型模式的浅复制,Copy方法不止复制了结构而且复制了数据,其实它就是原型模式的一个深复制。
Darren www.tianboo.net
分享到:
相关推荐
Darren设计之美
essayJoke 红橙Darren仿写内涵段子
Darren-s-project
本文实例为大家分享了js类式继承与原型式继承相关代码,供大家参考,具体内容如下 1.js类式继承 /* -- 类式继承 -- */ //先声明一个超类 function Person(name) { this.name = name; } //给这个超类的原型对象上...
darren_comm 通用代码
darren9080.github.io
Learn_darren_eassy_joke
电子取证行业一部知识点全面的书籍,适合电子取证不同阶段的人员阅读
《深入解析Spring MVCgn Web Flow》还介绍了Spring 框架的设计模式,以及如何将同样的设计和技术应用到读者自己的代码中。 《深入解析Spring MVCgn Web Flow》适合各层次Spring Web 程序员阅读。 编辑推荐 《深入...
Darren-greenhand.github.io
This powerful, practical book, based on years of proven and profi table experience, shows you how to leverage your special talents to maximize the opportunities surrounding you. The Compound Effect is...
内容提要 本书是目前Ajax领域最为全面深入的一本著作,其中不仅有对于基础知识的介绍,还有对于Ajax开发中重大的体系架构问题的深入探讨,总结了大量Ajax开发中的设计模式,并讨论了框架、安全性与性能等等。...
《Ajax实战》是目前Ajax领域最为全面深入的一本著作,其中不仅有对于基础知的的介绍,还有对于Ajax开发中重大架构问题的深入探讨,总结了大量Ajax开发中的设计模式,并讨论了框架、安全性与性能等。书中提供了几个...
honours_project Darren Lally的Honors项目,学生编号:S1622370-该项目是使用Django Web Framework开发的。 项目名称:调查哪些因素有助于使用Python和Django-FrameworkSwift发展,而不是使用PHP来开发Web应用程序...
这是一个类似通讯录,使用的是AlphabetIndexer快读定位
Darren Korb:晶体管之声 量子——埃里克·齐默尔曼 Grim Fandango 的制作 编程 游戏编程模式书 编码游戏 WebGL 工作坊 3D 计算机图形简介 面向对象编程初学者指南 设计文件 编写您的团队可以实际使用的 GDD 老...
可以下拉刷新的scrollView,代码可以运行注释也很详细,是个不错的资源
单元18 PWA作业:在线/离线预算跟踪器 向我们现有的Budget Tracker应用程序中添加功能,以允许脱机访问和功能。 无论有没有连接,用户都可以在他们的预算中增加支出和存款。 脱机输入事务时,它们应在重新联机后...
小巧的客户端应用概括Petful是另一种动物庇护所。 宠物应用程序的访问者只能收养在那里逗留时间最长的狗和/...科技栈该应用是使用React.js,Redux,Node.js和Express创建的。 客户端和服务器都由Heroku托管。乐于采用!
该存储库随附Darren James Harkness的 (Apress,2004年)。 使用绿色按钮将文件下载为zip格式,或使用Git将存储库克隆到您的计算机上。 发行版 版本v1.0对应于已出版书籍中的代码,没有更正或更新。 会费 请参阅...