设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 11504|回复: 42
打印 上一主题 下一主题

[原创发布] 【新手互助】利用Mix-in(糅合)构建低耦合脚本

[复制链接]

Lv1.梦旅人

梦石
0
星屑
55
在线时间
14 小时
注册时间
2008-5-7
帖子
74
跳转到指定楼层
1
发表于 2010-8-19 12:51:09 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
写在最前:以下观点来源于新手对RGSS脚本系统的一些浅显认知,希望能够给其他新手一些启发;牛人请直接跳过。如感觉不妥,请善意的指出;对于自认为很牛的无故拍砖者,一律鄙视!
原文链接:http://rpg.blue/home.php?mod=spa ... id=47826&id=689

include(module ... ) 对指定模块的性质(方法或常数)进行添加。返回 self。include 正是为实现 Mix-in(糅合)功能而设计的,而 Mix-in 取代了多重继承。
以上为RM中针对于关键字include的官方解释,本篇后续的内容亦是围绕此关键字展开。
Train_Actor是我接触RGSS以来遇到的第一个脚本系统,原帖可参见本坛脚本库,我空间里也有。用过的人应该都知道,只要借助于它便可轻易的实现角色跟随的特效。而引入此脚本的方法也很简单,只要在Main之前插入一段新脚本页,全部内容Copy即可。可谓便捷、经典。

第一次用这个脚本的时候觉得很神奇:该脚本完全独立,而系统是如何在恰当时机自动调用这个新增脚本内部方法的呢?经过一些简单的验证之后,终于渐渐发现了问题所在。

不知大家有没有留意到,该脚本的末端,也就是在module Train_Actor声明完毕之后,还有如下代码:

class Game_Party
include Train_Actor::Game_Party_Module
end
class Game_Player
include Train_Actor::Game_Player_Module
end
class Spriteset_Map
include Train_Actor::Spriteset_Map_Module
end
class Scene_Map
include Train_Actor::Scene_Map_Module
end

结合官方对于include的解释,不难猜想,这种独立脚本的自动调用机制即是由此而来。

所谓“对指定模块的性质(方法或常数)进行添加”,简单而言,也就是让自己脚本中已定义模块的方法或常数,成为指定模块中相应方法的逻辑补充。即是说,系统在调用原有模块内部方法的同时,会自动对已经被include至该模块的其他模块内部方法或常数进行调用。

有点绕口,我们不妨作如下实验来说明问题:

Main之前插入一个新脚本页,名字随便,而后写入如下代码:

module TestInclude
    def update
    p "外部方法被调用"   #验证一下自己的方法是否被调用
    super
    end
end
class Game_Player
    include TestInclude
end

代码很简单也很好理解,定义一个名为TestInclude的模块,此模块内部含有一个update方法,之后我们将此模块include至Game_Player模块,这样一来,系统对Game_Player的update方法调用完毕之后将自动调用TestInclude里的update——也就是说,我们自己模块中的方法成为了系统自带的Game_Player模块中update方法的逻辑补充。

点F12执行,则带有“外部方法被调用”字样的对话框会弹出。由于系统对于Game_Player里的update是一直调用的,因此我们自己模块里的update也会一直向外弹对话框,从任务管理器里将Game.exe扼杀掉即可。

之前也看过神思大人写的战斗CP脚本系统,有很多新人反应不知道该怎样引入自己的工程。我想如果借助于这种方法,神思大人完全可以将自己的CP系统也改装成不依赖于原有系统脚本且随用随引的独立系统了。

至于官方注释中提到的多重继承,这是C++中一种稍复杂的机制,这里不再讨论。其实在本人看来,Mix-in更像是多重反向继承。大家细心的话,应该就可以发现,对于include的外部模块,系统是优先调用原模块的方法,而后调用include模块中的方法,与C++中继承机制的调用顺序相反。

评分

参与人数 1星屑 +240 收起 理由
六祈 + 240 鼓励一下原创~~希望有更多人加入进来讨论~~ ...

查看全部评分

Lv3.寻梦者

孤独守望

梦石
0
星屑
3132
在线时间
1535 小时
注册时间
2006-10-16
帖子
4321

开拓者贵宾

43
发表于 2010-8-23 21:50:40 | 只看该作者
累计连贴多次,算上以前的一共50分,先记着,又发现的话一并算账;
看来是我的话引起了这一论战,那么抱歉。
我希望您要认识的是:在现代OOP当中,低耦合性显然是程序员们所追求的目标。
不可否认的是,本地C++由于其本身的特性,耦合性显然无法到达现代编程的安全要求的标准。全局性的友元方法和变量构成不安全的因素。
Ruby中作为规避高耦合性带来的风险,提供的方法为:用include方法进行的常量封装和alias进行的方法改造,甚至提供了安全系数$SAFE进行保护。
但是RGSS默认脚本所使用的大量全局变量已经破坏了Ruby的这一特性。
目前通行标准是:常量内部定义,或者Module封装include,方法用alias或者直接重写。

此帖不封,留待讨论。
菩提本非树,明镜本非台。回头自望路漫漫。不求姻缘,但求再见。
本来无一物,何处惹尘埃。风打浪吹雨不来。荒庭遍野,扶摇难接。
不知道多久更新一次的博客
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
55
在线时间
14 小时
注册时间
2008-5-7
帖子
74
42
 楼主| 发表于 2010-8-23 21:49:28 | 只看该作者
回复 六祈 的帖子
抱歉,六祈大人,或许是因为我始终没能摆脱6R给我的第一印象……带给您的麻烦,在此深表歉意……
不过,我很希望新手也能拥有自己的发言权,而不是仅仅只有在牛人后边跟帖或是当伸手党甚至于潜水党的份……
不如归去说的很对,正是因为有了先前被人鄙视的经验,所以才举起了这样的挡箭牌,但不是心安理得,而是一种无奈……
大家最初都是从新手的状态一点一点进步至今的,谁都有过幼稚的时候,如果能看到自己从前的影子,请试着相互谅解……

   

点评

那个帖子愚者也还记得,当时也只是二楼一句戏话。希望你莫要放在心上  发表于 2010-8-23 21:52
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
55
在线时间
14 小时
注册时间
2008-5-7
帖子
74
41
 楼主| 发表于 2010-8-23 21:31:04 | 只看该作者
本帖最后由 独孤残云 于 2010-8-23 21:34 编辑

回复 不如归去 的帖子
说的有道理,但请您看在一个新手公开了自己仅有的一丁点经验的前提上加以谅解,可以吗?虽然那对您这样的高手而言是不值一看的破玩意儿。


   
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
55
在线时间
14 小时
注册时间
2008-5-7
帖子
74
40
 楼主| 发表于 2010-8-23 21:28:10 | 只看该作者
本帖最后由 独孤残云 于 2010-8-23 21:29 编辑

回复 六祈 的帖子
呵~ 多谢六祈大人这样给足一个新手面子~
之所以写这个的目的,最初只是因为看到很多新人在神思大人的CP系统下跟帖,询问除了引入新脚本之外还需要做哪些改动。所以提供一点参考意见,方便自己也方便别人。
帖子的内容一开始就旨在讨论如何降低自己新增的脚本与原脚本系统间的耦合,说白了,就是写出的系统能让一个用它的新手简简单单引入一个新脚本页即可,而并非讨论整个RGSS系统耦合度的高低问题。单就这一点,我相信我明白,很多人也都明白,但您确确实实没明白。
如果您认为Ruby新手的身份不足以与您一起品头论足,那我可以告诉您,很多编程语言都具备类似的共通点,至于全局变量,更是C++基本中的基本。所以,请不要随随便便以老手的身份认定Ruby新手同样会缺乏基本常识。
至于“绵里藏针”,呵~人本身便是棉针一体,可以针对一部分人来保护自己,但却不能误伤无辜的人,这个道理,六祈大人应该明白吧?
最后,您大力推荐的alias,我只能尽自己的努力去研究,然后尽可能的分享一点自己的破陋见解。六祈大人很强,这点我深信不疑,如果能得到您的指导,我当然高兴。但我还是那句话,新手的东西,不可能经得住一句话一句话的推敲,希望能理解。至于Ruby机制本身存在的缺陷,反正我是无能为力的。

   

点评

愚者绝没有看轻你,所以你也不要妄自菲薄。希望能更多看到你讨论技术的内容,而不是来和愚者争论无谓的问题  发表于 2010-8-23 21:35
回复 支持 反对

使用道具 举报

Lv1.梦旅人

归去之风<

梦石
0
星屑
50
在线时间
14 小时
注册时间
2010-8-5
帖子
45

开拓者

39
发表于 2010-8-23 21:09:25 | 只看该作者
本帖最后由 不如归去 于 2010-8-23 21:15 编辑

”新手讨论“不是各种幼稚思想的挡箭牌。
不如归去,风吹的那么刺骨。
又何必再这样流连,曾经的流年已如风般逝去
回复 支持 反对

使用道具 举报

Lv2.观梦者

旅之愚者

梦石
0
星屑
275
在线时间
812 小时
注册时间
2007-7-28
帖子
2148

贵宾

38
发表于 2010-8-23 20:49:11 | 只看该作者
回复
谢谢分子兄提醒,是我太较真了^_^
不过,我是真的很希望六祈版主能明白里边的道理,绝没有别的意思~
...
独孤残云 发表于 2010-8-23 12:38

绵里藏针话中带刺不是讨论的做法,如果你对愚者有何不满可以直说,版主的权限愚者只会依版规而用
希望xxx明白这种话说起来似乎是愚者不懂而您懂了【应该没曲解吧】,既然说这样的话又何必惺惺的说绝没有别的意思呢?

回到我一开始触痛您的话,愚者说您没有基本常识,理由如下:
IamI说rm脚本天生的大量使用了全局变量,已无耦合性可言
【诚恳的说,愚者不是软工的,也不懂耦合度,于是大致理解为代码的相互依赖度和侵入度,如若有误,请指出】
对于一个翻过几遍F11的人来说,应该是懂得$data_xxx和$game_xxx这些的,几乎充斥了整个游戏的全部进程
既然你说怎么做不到低耦合度,于是愚者很简单的理解为您没怎么浏览过F11的默认脚本【ok,愚者之前那句的观点仅仅在此,如果有错,向你道歉】

【回到帖子的主题】把我想表达的意思全部写出来:
写脚本,低耦合度意味着更少的整合和调试
于是要做到:
【对原脚本的破坏性要小】
【与其它脚本兼容性要好】
后面说到super调用的问题,对于原类没有的方法,混入模块就能获得方法,这个最简单,但是有时候难免会因为其它脚本的缘故而导致命名被占。

已有的方法要用super来调用混入模块的方法,而混入模块的方法又要用super来调用原父类的方法

如果只是默认脚本的基础上加入一个人的混入模块,还可以通过一一查看原类是否已有方法来解决。如果是在其它脚本师的脚本之后加入呢?【有没有同名方法,有的话那么有没有super,没super同名方法等于没写,有super不写就完了。没有同名方法写了super又是悲剧】这个需要考虑的东西数量会很多

这些就是后面我想表达的关于include的潜在问题【也许是因为愚者才疏学浅】。

另外这样的看法是相对alias而来的,alias的技巧从设计模式的角度来讲,应该算装饰器模式,每个脚本师都可以在之前的基础上添加自己的语言而不会和其它脚本师的脚本冲突【或者说不容易】

以上为愚者拙见,望楼主不吝赐教
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
55
在线时间
14 小时
注册时间
2008-5-7
帖子
74
37
 楼主| 发表于 2010-8-23 20:26:33 | 只看该作者
回复 DeathKing 的帖子
版主大人莫要误会,我绝没有要针对谁的意思~ 只不过会不习惯随随便便就被人认定缺乏“基本常识”。
对于Ruby中很多机制的理解都还留有C++的影子,这些东西以后会记得跟您多多请教的~

   
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
55
在线时间
14 小时
注册时间
2008-5-7
帖子
74
36
 楼主| 发表于 2010-8-23 20:12:49 | 只看该作者
回复 BBBBB6 的帖子
DeathKing版主的个人签名里推荐的:http://rpg.blue/misc.php?mod=faq,好像挺不错的。话说我也是刚刚开始摸索的。
不要着急,先慢慢来吧~

   
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
29 小时
注册时间
2010-7-5
帖子
483
35
发表于 2010-8-23 19:58:44 | 只看该作者
回复 独孤残云 的帖子
我可是只知道条件分歧的脚本啊。。。从头开始呢。。。有没有什么好的教程推荐啊。。。

   
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-28 01:24

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表