前回は練習と通常の開発モデルとの比較に専念していましたが、今回は技術の理論的基礎についてお話したいと思います。
説明を簡単にするために、Context-Object-Request-Eventシステムからコンテキストを破棄し、タスクの設定と、それらがオブジェクト、イベント、リクエストにどのように関連するかについて説明します。
問題の記述と流れるような抽象化
プログラミングでは、頻繁に流れる抽象化に対処する必要があります。 たとえば、データベースへの接続が落ちる可能性があることをコードで考慮していない場合、問題が発生します。
流れる抽象化にはさらに根本的な問題があり、複雑な動作のモデリングに関係しています。 タスクに追加の要件が追加されると、作成されたばかりのコードが使用できなくなり、すべてをやり直す必要が生じることがよくあります。 これもまた進行中の抽象化です。問題の解決策を、問題の観点からではなく、変数、リスト、リンク、オブジェクト、デザインパターンといったプログラミング言語の観点からモデル化しました。 要件がわずかに変更されたため、コード全体が使用できなくなりました。
これは、プログラミング言語が、定式化で使用するタスク記述言語と類似していないためです。
実際のタスクのほとんどは、「AがBを実行するとき」と「Cを実行する必要がある。Dの方法で実行する」という2つのパターンに分類されることを確認します。
次の表記法を導入します。Aはイベント、Bはイベントへの反応、Cはアクションの要求、Dは実行方法です。
最初のケースの例:
-ユーザーがこのボタンをクリックしたら、このアニメーションを表示しましょう(うーん、会議のように)
-デザイナーのアーニャがインターフェースのプロトタイプを描くとき、私はそれを見て、改善についての私の考えを表現したい
-クリックごとに統計を収集しましょう
-5回目の実行ごとにバナーを表示します
2番目の場合:
-このアイデアのデザインを描く必要があります。 アーニャにやらせてください。 まあ、または、Vova。
-現在のアカウントの値をデータベースに保存する
次の点に注意してください:最初の場合のタスクの本質は、Aが発生したときにBを実行することであり、Aが何であるか、どの特定のコンテキストが発生したかなどは関係ありません。 また、このタスクは、イベントAが発生するタスクとは完全に分離されており、他の目標に専念しています。 2番目のケースでは、逆です。 タスクCがどのように行われるかはまったく関係ありません。少なくとも何らかの形で適切な方法で行われることが重要です。
これを理解することが重要なのはなぜですか? 次のjsの抽象的なゲームコード(またはその他のもの)を検討してください。
addMoney: function(amount) { this.balance+=amount; if(this.balance > 250) { $('.you_win!').animate({css:{opacity: 1}}) } }
このコードは非常に悪いです。 なんで? それはお金の論理が表示の論理と混ざり合っているからです。 さらに悪いことに:
$('.coin').click(function(){ this.balance+=15; if(this.balance > 250) { $('.you_win").animate({css:{opacity: 1}}) } })
プロトタイプでは、このような例は非常に頻繁に発生します。 タスクのあらゆる側面-デザイン、お金のカウント、アニメーション-をすべて、カヤックに触れてください。それはすぐに混乱に変わり、失敗します。 通常の方法 タスクの内容を説明してください:
-ユーザーがコインをクリックしたときに、残高に追加します
-残高が250を超える場合、獲得したバナーを表示します
タスクを3つのオブジェクトに分割します。1つは表示とUI、2つ目はアカウントの状態、3つ目はユーザーの勝敗を決定します。
var UI = { handleCoinClick: function() { .... }, showWinAnimation: function() { .... }, ... } var Balance = { addCoins: function() { ... }, ... } var WinWatcher = { watchForWin: function() { .... } ... }
ここのUIは、表示とクリック-ユーザーインタラクションのみを担当します。
ここで、これらのコンポーネントを何らかの方法で接続する必要があります。 相互に呼び出すのは良くないので、イベントやリクエストに接続します
var UI = { handleCoinClick: function() { // , DOM Init, , .... $('.coin').click(function(){ // Event_CoinClick ..... }); }, showWinAnimation: function() { // , Request_ShowUserWin $('.you_win').animate({opacity: 0}); }, ... } var Balance = { addCoins: function() { // , « » Event_CoinClick this.balance+=15; // , Event_BalanceChanged }, ... } var WinHandler = { watchForWin: function(balance) { // , , Event_BalanceChanged if(balance > 250) { // , Request_ShowUserWin } } ... }
ここで、コメントが「…を呼び出す」および「ここにドロップ/リクエストする」というコメントのあるコードをリンクする必要があります。 しかし、ここでは、同じ流れるような抽象化に直面しています。 BalanceメソッドとWinHandlerメソッドをUIから直接呼び出す場合、統計情報やその他の複雑な情報を収集する必要があり、他のタスクに関連する呼び出しがUIメソッドに追加されます。 メソッドはクリーンでなくなります。
したがって、メソッドをシンプルにするようにします。 イベントディスパッチャーに依存関係の解決を提供する
Core.js
前回、オープンソースの実装を行うことを約束しました。 現在、javascript github.com/okneigres/corejsの実装があります
ライブラリはブラウザとNode.jsの両方で機能します
<script src="core.js"></script> var Game = { }; // Game.UI = { CoinClickEvent: new Core.EventPoint, handleCoinClick: function() { Core.CatchEvent(Event.DOM.Init); $('.coin').click(function(){ new Game.UI.CoinClickEvent(); }); }, showWinAnimation: function() { Core.CatchRequest(Game.WinHandler.ShowUserWinRequest); $('.you_win').animate({opacity: 0}); }, ... } Game.Balance = { ChangedEvent: new Core.EventPoint, addCoinsOnClick: function() { Core.CatchEvent(Game.UI.CoinClickEvent) this.balance+=15; new Game.Balance.ChangedEvent; } ... } Game.WinHandler = { ShowUserWinEvent: new Core.EventPoint, ShowUserWinRequest: new Core.RequestPoint, watchForWin: function(balance) { Core.CatchEvent(Game.Balance.ChangedEvent) if(balance > 250) { new Game.WinHandler.ShowWinRequest; } } ... } Core.processNamespace(Game);
このコードを使用すると、何でも簡単に実行できます。新しい機能を追加します。
// Game.GatherStat = { sendClick: function() { Core.CatchEvent(Game.UI.CoinClickEvent); $.post('/stat/gather/ajax', {click: 1, date: new Date}); }, sendWin: function() { Core.CatchEvent(Game.WinHandler.ShowUserWinEvent); $.post('/stat/gather/ajax', {win: 1, date: new Date}); } }
UIのリファクタリング(2つのオブジェクト-UIとUIWinに分割):
Game.UI = { CoinClickEvent: new Core.EventPoint, handleCoinClick: function() { Core.CatchEvent(Event.DOM.Init); $('.coin').click(function(){ new Game.UI.CoinClickEvent(); }); } }; Game.UIWin = { showWinAnimation: function() { Core.CatchRequest(Game.WinHandler.ShowUserWinRequest); $('.you_win').animate({opacity: 0}); }, ... };
コードはロジックに厳密に従って記述されているため、コードの操作は簡単です。
結論の代わりに
このようなパラダイムで作業すると、プロジェクトの設計とコンテンツが大幅に簡素化されます。 何度でも改造できますが、タスクのロジックは同じままです。 それからコードを作成してみませんか? 少し練習すれば、そのようなパラダイムで働くことができます。実際、私たちはそれについて考える言葉でタスクを説明するだけなので、それはすべてです。
私の経験では、これにより、インターフェースの設計、さらにはサーバーアプリケーションの設計が大幅に簡素化されます。 タスクが必要とする抽象化レベルでコードを含めることは可能であり、必要です。