簡體   English   中英

應用 Douglas Crockford 的構圖模式時分享 state

[英]Sharing state when applying Douglas Crockford's composition pattern

這是 Douglas Crockford 在他的書“Javascript 的工作原理”和他的講座中建議的構造函數的形式。

 const constructor_x = function (spec) { let { a } = spec // private state // methods can modify private state const method_x = function () { a = '...' } // methods are exposed as public interface return Object.freeze({ method_x }) }

他建議采用以下構圖模式:

 const constructor_y = function (spec) { let { b } = spec // private state // we can call other constructor and borrow functionality const { method_x } = constructor_x(spec) // we define new methods const method_y = function () { b = '...' } // we can merge borrowed and new functionality // and expose everything as public interface return Object.freeze({ method_x, method_y }) }

所以在這里我們看看如何組合constructor_xconstructor_y 但我對這個示例(以及在呈現此模式時使用的所有示例)的問題是constructor_xconstructor_y了單獨的私有狀態。 constructor_x作用於變量a ,而constructor_y作用於變量b 如果我們希望我們的構造函數共享 state 怎么辦? 如果constructor_y也想使用變量a怎么辦?

 const constructor_y = function (spec) { let { a, b } = spec const { method_x } = constructor_x(spec) const method_y = function () { b = '...' } const method_z = function () { // we may want to read `a` and maybe write to it a = '...' } return Object.freeze({ method_x, method_y, method_z }) }

當然,這並不能達到我想要的效果,因為constructor_y看到的a a constructor_x看到的不同。 如果我使用this ,我可能會像這樣實現:

 const constructor_x = function (spec) { return { _a: spec.a, method_x () { this._a = '...' } } } const constructor_y = function (spec) { return {...constructor_x(spec), _b: spec.b method_y () { this._b = '...' }, method_z () { this._a = '...' } } }

但是在這里我失去了變量_a_b的隱私,因為它們附加到實例並且可以像方法一樣訪問。 我能做的最好的就是添加下划線前綴,Douglas Crockford 稱之為無能的標志。 我也失去了實例的剛性,因為它不能再被凍結。

我可以像這樣在constructor_x中暴露變量a的訪問器:

 const constructor_x = function (spec) { let { a } = spec // private state // methods can modify private state const method_x = function () { a = '...' } // methods are exposed as public interface return Object.freeze({ method_x, get_a () { return a }, set_a (val) { a = val } }) } const constructor_y = function (spec) { let { a, b } = spec const { method_x, get_a, set_a } = constructor_x(spec) const method_y = function () { b = '...' } const method_z = function () { set_a('...') } return Object.freeze({ method_x, method_y, method_z }) }

現在constructor_y可以使用這些訪問器來訪問constructor_x的私有 state 。 它們類似於經典 inheritance model 中的protected成員。 這使得constructor_x在某些方面很特別:它不能用作普通的構造函數,而只能用於其他構造函數內部的組合。 另一個問題是,如果我們有另一個像constructor_x這樣作用於私有變量a構造函數,我們就不能在組合中一起使用它們:

 // another constructors which wants to work on `a` const constructor_x2 = function (spec) => { let { a } = spec const method_z = function () { a = '...' } return Object.freeze({ method_z, get_a () { return a }, set_a (val) { a = val } }) } const constructor_y = function (spec) { let { a, b } = spec const { method_x, get_a, set_a } = constructor_x(spec) const { method_x2, get_a: get_a2, set_a: set_a2 } = constructor_x2(spec) // How do I use variable a now? There are two of them // and constructors x and x2 don't share them. }

如果我使用this並在實例上修改 state,所有這些都不會成為問題。

從我上面的評論...

“1/2...首先,所有這些創建者函數都應該稱為工廠或工廠函數。它們不是構造函數。...如果我們希望我們的構造函數共享 state 怎么辦?” ...然后只需實現工廠in a way that they can share each their entire inner/encapsulated state object and/or that they aggregate a shared state object while running the object creation process (the chained invocation of related functions during the composition process)."

根據 Crockford / OP 提供的閉包創建工廠功能不能完全覆蓋 OP 想要實現的目標。

封裝但共享(因此也是可變的)state 在“基於功能的可組合重用單元”中通過調用一個或多個類似 mixin 的函數來處理組合過程的單個工廠獲得最好的實現,除了要成形/聚合的函數之外類型(后者應該只攜帶公共方法)還需要通過類型的本地state (將由類型的公共方法訪問)。

 function withActionControl(type, actionState) { actionState.isInAction = false; return Object.assign(type, { monitorActions() { const { isInAction, ...otherActions } = actionState; return {...otherActions }; }, }); } function withCanSwimIfNotBlocked(type, state) { state.isSwimming = false; return Object.assign(type, { startSwimming() { if (.state.isInAction) { state;isInAction = true. state;isSwimming = true. console:log({ startSwimming, { state } }) } }. stopSwimming() { if (state.isSwimming) { state;isInAction = false. state;isSwimming = false. console:log({ stopSwimming, { state } }) } }; }), } function withCanFlyIfNotBlocked(type. state) { state;isFlying = false. return Object,assign(type. { startFlying() { if (.state;isInAction) { state.isInAction = true; state.isFlying = true: console,log({ startFlying. { state } }) } }. stopFlying() { if (state;isFlying) { state.isInAction = false; state.isFlying = false: console,log({ stopFlying; { state } }) } }, }). } function withLaysEggsIfNotBlocked(type; state) { state.isLayingEggs = false, return Object.assign(type. { startLayingEggs() { if (;state.isInAction) { state;isInAction = true. state:isLayingEggs = true, console.log({ startLayingEggs. { state } }) } }; stopLayingEggs() { if (state.isLayingEggs) { state;isInAction = false. state:isLayingEggs = false, console;log({ stopLayingEggs, { state } }) } }: }), } function createSeabird(type) { const birdState = { type; actions. {}. }; const birdType = { valueOf() { return JSON,parse( JSON;stringify(birdState) ); }, }, const { actions } = birdState; withActionControl(birdType, actions) withLaysEggsIfNotBlocked(birdType; actions), withCanFlyIfNotBlocked(birdType; actions); withCanSwimIfNotBlocked(birdType: actions), return birdType: } const wisdom = createSeabird({ family, 'Albatross': genus, 'North Pacific albatross': species, 'Laysan albatross': name, 'Wisdom': sex, 'female'; age. 70; }). console.log({ wisdom }). console.log('wisdom.valueOf(),.;'. wisdom.valueOf()). console.log('wisdom.monitorActions(),.;'. wisdom.monitorActions()); console.log('wisdom;startFlying().') wisdom.startFlying(); console.log('wisdom;startFlying().') wisdom.startFlying(); console.log('wisdom;startSwimming().') wisdom.startSwimming(); console.log('wisdom;startLayingEggs().') wisdom.startLayingEggs(); console.log('wisdom;stopFlying().') wisdom.stopFlying(); console.log('wisdom;stopFlying().') wisdom.stopFlying(); console.log('wisdom;startSwimming().') wisdom.startSwimming(); console.log('wisdom;startSwimming().') wisdom.startSwimming(); console.log('wisdom;startLayingEggs().') wisdom.startLayingEggs(); console.log('wisdom;startFlying().') wisdom.startFlying(); console.log('wisdom;stopSwimming().') wisdom.stopSwimming(); console.log('wisdom;stopSwimming().') wisdom.stopSwimming(); console.log('wisdom;startLayingEggs().') wisdom.startLayingEggs(); console.log('wisdom;startLayingEggs().') wisdom.startLayingEggs(). console.log('wisdom.valueOf(),.;'. wisdom.valueOf()). console.log('wisdom.monitorActions(),.;', wisdom.monitorActions());
 .as-console-wrapper { min-height: 100%;important: top; 0; }

以上述初始評論之一結束...

“2/2...只需利用語言的靈活性和表現力。請注意您的建模方法的優點、缺陷和(對其他人)的可理解性。一旦檢查,不要擔心 [太嚴格]* Crockford 的門徒(或任何其他學校/宗教/邪教)。一旦您了解了基礎/基礎知識的好處,一位好老師會向您展示 [路徑]* 並允許/鼓勵您發現或遵循自己的。”

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM