对方法过度收费是个好主意吗?
Is it a good idea to overcharge a method?
我有3个类,都是上一个的扩展
实体 -> Body -> 玩家
每个都有一个 die()
方法,可以做非常不同的事情。
Entity.die()
将调用 db
Body.die()
将为 body
设置动画
Player.die()
将调用 UI 并播放特殊声音。
我不想在Body.die
方法里面手动调用Entity.die()
,主要是因为我有很多类和很多常用的方法,我不想忘记一些东西。
我写的这段代码正是这样做的,错误堆栈很容易理解并指向正确的行。
function overLoadMethods (parent, children) {
const methods = {}
for (let [fname, fn] of Object.entries(parent)) {
if (typeof fn === 'function') {
if (children[fname]) {
methods[fname] = function () {
fn()
children[fname]()
}
Object.defineProperty(methods[fname], 'name', { value: fname })
} else {
methods[fname] = fn
}
}
}
return methods
}
function createEntity () {
return {
die: () => {
console.log(new Error().stack)
console.log('entity die')
}
}
}
const bodyMethods = {
die: () => {
console.log(new Error().stack)
console.log('body die')
}
}
function createBody () {
const entity = createEntity()
const overLoadedMethods = overLoadMethods(entity, bodyMethods)
return {
...entity,
...bodyMethods,
...overLoadedMethods
}
}
const playerMethods = {
die: () => {
console.log(new Error().stack)
console.log('player die')
}
}
function createPlayer () {
const body = createBody()
const overLoadedMethods = overLoadMethods(body, playerMethods)
return {
...body,
...playerMethods,
...overLoadedMethods
}
}
const player = createPlayer()
// will call Entity.die() then Body.die() then Player.die()
player.die()
一切正常,但我以前从未见过这种模式,我想这其中有一个我不知道的充分理由。
如果有的话(很确定有),有人能指出这种模式的弱点吗?
我理解不重复代码和创建难以犯错和忘记事情的代码的愿望。但是您仍然需要记住连接的代码。例如,您需要调用 overLoadMethods()
而不是调用 Entity.die()
。我不确定这是否比常规 类 和调用 super.die()
.
有所改进
您可以使用 ES6 类 获得链式方法行为(您也可以使用原型获得它)。这有很多优点:
• 模式融入了语言。
• 很明显parent/child关系
• 有很多不同模式的评论、理论和示例
class Entity {
die() {
// Entity-specific behavior
console.log('entity die')
}
}
class Body extends Entity {
die() {
super.die()
// Body-specific behavior
console.log('body die')
}
}
class Player extends Body {
die() {
super.die()
// Player-specific behavior
console.log('player die')
}
}
const player = new Player
// will call Entity.die() then Body.die() then Player.die()
player.die()
Common Lisp 有 something similar。当你在派生中定义一个方法时class你可以决定这个方法是否应该被执行:
:before
(即基础方法会在特化后自动调用)
:after
(即基本方法将在专用方法之前自动调用)
:around
(即只调用专门的方法,但在其主体内您可以使用 call-next-method
调用基方法,这是一种特殊语法,允许使用参数调用基方法由调用者指定或您要传递的参数代替)。
例如,C++ 只有 around
可用于一般方法(但无法使用原始参数调用基本版本),并强制在构造函数中使用 before
和 after
在析构函数中。
我有3个类,都是上一个的扩展
实体 -> Body -> 玩家
每个都有一个 die()
方法,可以做非常不同的事情。
Entity.die()
将调用 db
Body.die()
将为 body
设置动画
Player.die()
将调用 UI 并播放特殊声音。
我不想在Body.die
方法里面手动调用Entity.die()
,主要是因为我有很多类和很多常用的方法,我不想忘记一些东西。
我写的这段代码正是这样做的,错误堆栈很容易理解并指向正确的行。
function overLoadMethods (parent, children) {
const methods = {}
for (let [fname, fn] of Object.entries(parent)) {
if (typeof fn === 'function') {
if (children[fname]) {
methods[fname] = function () {
fn()
children[fname]()
}
Object.defineProperty(methods[fname], 'name', { value: fname })
} else {
methods[fname] = fn
}
}
}
return methods
}
function createEntity () {
return {
die: () => {
console.log(new Error().stack)
console.log('entity die')
}
}
}
const bodyMethods = {
die: () => {
console.log(new Error().stack)
console.log('body die')
}
}
function createBody () {
const entity = createEntity()
const overLoadedMethods = overLoadMethods(entity, bodyMethods)
return {
...entity,
...bodyMethods,
...overLoadedMethods
}
}
const playerMethods = {
die: () => {
console.log(new Error().stack)
console.log('player die')
}
}
function createPlayer () {
const body = createBody()
const overLoadedMethods = overLoadMethods(body, playerMethods)
return {
...body,
...playerMethods,
...overLoadedMethods
}
}
const player = createPlayer()
// will call Entity.die() then Body.die() then Player.die()
player.die()
一切正常,但我以前从未见过这种模式,我想这其中有一个我不知道的充分理由。 如果有的话(很确定有),有人能指出这种模式的弱点吗?
我理解不重复代码和创建难以犯错和忘记事情的代码的愿望。但是您仍然需要记住连接的代码。例如,您需要调用 overLoadMethods()
而不是调用 Entity.die()
。我不确定这是否比常规 类 和调用 super.die()
.
您可以使用 ES6 类 获得链式方法行为(您也可以使用原型获得它)。这有很多优点:
• 模式融入了语言。
• 很明显parent/child关系
• 有很多不同模式的评论、理论和示例
class Entity {
die() {
// Entity-specific behavior
console.log('entity die')
}
}
class Body extends Entity {
die() {
super.die()
// Body-specific behavior
console.log('body die')
}
}
class Player extends Body {
die() {
super.die()
// Player-specific behavior
console.log('player die')
}
}
const player = new Player
// will call Entity.die() then Body.die() then Player.die()
player.die()
Common Lisp 有 something similar。当你在派生中定义一个方法时class你可以决定这个方法是否应该被执行:
:before
(即基础方法会在特化后自动调用):after
(即基本方法将在专用方法之前自动调用):around
(即只调用专门的方法,但在其主体内您可以使用call-next-method
调用基方法,这是一种特殊语法,允许使用参数调用基方法由调用者指定或您要传递的参数代替)。
例如,C++ 只有 around
可用于一般方法(但无法使用原始参数调用基本版本),并强制在构造函数中使用 before
和 after
在析构函数中。