質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

3回答

2285閲覧

メイン処理にチェック処理を記述しないデザインパターン

退会済みユーザー

退会済みユーザー

総合スコア0

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

2クリップ

投稿2018/01/03 05:57

編集2018/01/03 15:17

デザインパターンについて、まだ体系的に学んでいない初心者です
(シングルトン云々言われても、そういう手法があるんだな程度です)。
また、過去の質問もあまり見返していないため、重複していたら申し訳ありません……

現在の処理は、以下のような形となっています。

JavaScript

1$(function(){ 2 // メイン処理 3 main(); 4 5 function main() { 6 // 処理Aを実行する 7 processA(); 8 9 // プロセスAで実行した内容が正しいかチェックする 10 isCheckedProcessA(); 11 12 // 処理Bを実行する 13 processB(); 14 15 // プロセスBで実行した内容が正しいかチェックする 16 isCheckedProcessB(); 17 18 // 処理Cを実行する 19 processC(); 20 } 21});

何だか、チェック処理が間に一々挟まって鬱陶しい気がしてます……
そこで、以下のような形にしたいと考えました。

▽理想

JavaScript

1$(function(){ 2 // メイン処理 3 main(); 4 5 function main() { 6 try { 7 processA(); // 処理Aを実行する 8 processB(); // 処理Bを実行する 9 processC(); // 処理Cを実行する 10 } 11 catch(processAEroor) { 12 } 13 catch(processBEroor) { 14 } 15 } 16});

これだとすっきりするんですけど、「じゃあどこでチェック処理やるの?」と考えたとき、
例えばprocessA処理中にエラーが発生した場合、processAの処理中で例外を飛ばすくらいしか
解決策が今のところ思い付きません……

processAのメソッド内のイメージ

JavaScript

1function processA() { 2 // 本来のprocessAの処理 3 // …… 4 // isCheckedProcessAの処理 5}

「いやいや、それって単にisCheckedProcessAprocessAに入れただけやんけ!」
ってなってます(´・ω・)
→**「メイン処理とチェック処理を本来分けてたものを、一緒のメソッドに入れると分かりにくそう」**
ってなってます(´・ω・)

そこで質問なのですが、処理を行うごとに入るチェック処理と
実際の処理を明確に分けたい場合、どのように記述すればいいですか?

ご教示のほど、よろしくお願いいたします。


▽以下、修正&加筆:

具体例に関して、修正依頼をいただきましたので、加筆いたします。
実際に、オセロのプログラムを組んでいてこの問題に直面しているため、それを例として挙げます。

JavaScript

1$(function(){ 2 3 $('li').click(function() { 4 // 選択された箇所のx座標、y座標を取得 5 var y = getPutY(); 6 var x = getPutX(); 7 8 // 相手の石がひっくり返せる座標を取得 9 getReversibleCoordinate(); 10 11 /** 12 * ここでチェック処理を入れないと、相手の石がひっくり返せなくても 13 * 自分の石が置けたり、手番が交代したりしてしまいます。 14 */ 15 if (isErrorPutStone()) { return; } 16 17 // 選択箇所に自分の石を置く 18 putStone(y, x); 19 20 // 相手の石をひっくり返す 21 reversibleEnemyStone(); 22 23 // 手番を交代する 24 turnChange(); 25 } 26 27 function getReversibleCoordinate() { 28 // 相手の石がひっくり返せる座標を取得 29 } 30 31 function isErrorPutStone() { 32 // 相手の石がひっくり返せる座標を取得できなかった場合を検証 33 // 自分の石が置けなかった場合を検証 34 } 35});

……なんだか、元の質問とは別の部分を指摘されそうですが。。
ロジックの組み方に関して、ツッコミ所があれば、ご指摘いただけると助かります(´・ω・)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

think49

2018/01/03 13:04

何の為に処理を分割するのでしょう。分割することが目的ではないはずで、最終的に到達したい動作を明らかにした方が良いと思います。また、チェック処理も具体性がないので全体像を想像しづらいように思います。
退会済みユーザー

退会済みユーザー

2018/01/03 13:53

修正依頼ありがとうございます。「分割することが目的ではない」というのは、確かに仰る通りです。……なのですが、この字面通り受け取ったとき「(ケースバイケースで)特に変える必要ないのかな?」と、曲解してしまいました。また、汎用的な書き方が却って分かり辛かったようで申し訳ありません……具体例は後ほど追記いたします。
think49

2018/01/03 14:03

"「(ケースバイケースで)特に変える必要ないのかな?」" 直観的には、変更前/変更後共に私は「使いたくないコード」と思ってしまいました。 processA() を実行後に isCheckedProcessA() は実行しなければならないのか、実行しなければならないなら別の名前に分離させる意味があるのか(因果関係があるなら、同じ名前空間に属するべきでは。分離するなら、独立させるメリットが必要。)。 try-catchはエラー処理で全て例外を投げなければならないのか、例外を投げられなかった場合は考慮しないのか(例外を投げないエラーを完全になくすのか)、など。
退会済みユーザー

退会済みユーザー

2018/01/03 14:45

返信ありがとうございます。すべてのご指摘を理解できたわけではありませんが、「理想的なコードが組めていたら、そもそもこのような書き方にはならない」と解釈いたしました。具体例を追記いたしましたので、そこでまたご指摘いただけると助かります。
guest

回答3

0

関数名

実際に、オセロのプログラムを組んでいてこの問題に直面しているため、それを例として挙げます。

processA() と isCheckedProcessA() がセットで実行されるように見えたのですが、

  • processA -> getReversibleCoordinate
  • isCheckedProcessA -> isErrorPutStone

このような対応関係なら、違いますね。

どうも関数名が好ましくない気がします。
例えば、isErrorPutStone を reversible (ひっくりかえせるか真偽値を返す関数) に名称変更してみてはいかがでしょうか。

参照透過性

基本的に、特別な理由がなければ参照透過性を持った関数が好ましいと感じます。
質問者さんのコードはざっくり書くとこんな感じです。

JavaScript

1(function () { 2 var x = 1, y = 2; 3 4 A(); 5 B(); 6 C(); 7 8 function A () { 9 console.log(x, y); 10 } 11 12 function B () { 13 ++x; 14 } 15 16 function C () { 17 ++y; 18 } 19}());

これはグローバル変数を使って、変数を共有しているのと実質的に同じです。
引数は全く使わず、参照透過性を完全になくしてしまっています。
せめて、次のように書きましょう。

JavaScript

1(function () { 2 function console (x, y) { 3 console.log(x, y); 4 } 5 6 function incrementX (x) { 7 return ++x; 8 } 9 10 function incrementY (y) { 11 return ++y; 12 } 13 14 function main () { 15 var x = 1, y = 2; 16 17 console(x, y); 18 x = incrementX(x); 19 y = incrementY(y); 20 } 21 22 main(); 23}());
  • 入力値は出来るだけ引数で渡してください。
  • 出力は原則として、返り値に持たせて下さい。
  • 関数名は単体としてみても意味の通る名前にして下さい。
    関数Aに付属するcheckAなど、もってのほかです。
    チェックするのなら何をどのようにチェックするのか、具体的な処理内容を踏まえた名前にしましょう。

改善案

無駄を排除していくと、次のコードを書けると思います。

JavaScript

1jQuery(function(jQuery) { 2 function getReversibleCoordinateList (x, y) { 3 // 指定した座標及び相手の石がひっくり返せる座標を配列で返す 4 } 5 6 function setStone(color, coordinateList) { 7 // 対象の全座標を指定色の石で埋める 8 } 9 10 function handleClick (event) { 11 var li = event.target; // クリックされた要素を取得 12 13 // 選択された箇所のx座標、y座標を取得(data-x, data-y 属性に予め、座標を埋め込んでおく) 14 var x = li.dataset.x; 15 var y = li.dataset.y; 16 17 // 相手の石がひっくり返せる座標を取得 (石を置いた座標も合わせて取得) 18 var reversibleCoordinateList = getReversibleCoordinate(x, y); 19 20 // 座標の数が2未満なら強制終了 (座標の数が1なら石を置いた座標しか得られていないので、ひっくり返る石は0) 21 if (reversibleCoordinateList.length < 2) { 22 return; 23 } 24 25 var data = event.data, 26 color = data.color; 27 28 // 対象座標を指定色の石で埋める(石を置き、相手の石をひっくり返す) 29 putStone(color, reversibleCoordinateList); 30 31 // 手番を交代する 32 data.color = data.color === 'black' ? 'white' : 'black'; 33 } 34 35 jQuery('li').on('click', {color: 'black'}, handleClick); 36});

元のコードを尊重して「座標」としましたが、変数 reversibleCoordinateList は「li要素ノードの配列」にすると反転処理が実装しやすいと思います。

今後の発展形としては「classパターン」にすると、ページ上にオセロがいくつも作れて便利ですね。

Re: icicle さん

投稿2018/01/03 17:27

編集2018/01/03 17:53
think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/01/05 04:11 編集

具体的なオセロの修正案含め、回答いただき本当にありがとうございます。 なるほど……ひっくり返せる座標は全部まとめて一つに入れてしまえばいいんですね。 言われてみれば確かに、となるのですが……一人で思い付くのは難しいですね…… ご提示いただいた改善案で、もう一度組み直してみようと思います。 コード修正後、改めてコードレビュー依頼の旨の質問を行うかもしれません。
退会済みユーザー

退会済みユーザー

2018/01/05 09:37

こちらを参考に実際に組んでいる途中ですが、質問前と比較にならないほど コードがすっきりして驚きました。。既に50行近く削れた気がします。 関数名の付け方だけでここまで変わるものなんですね…… 所感コメント失礼しました。
guest

0

JavaScript

1 processA(); 2 isCheckedProcessA(); 3 processB();

processB() の前に必ず isCheckedProcessA() が必要なのであれば、チェックを processA() の末尾ではなく processB() の始めに置きましょう。

これをガードと言います。
つまり次のようになります。

JavaScript

1function processB() { 2 // isCheckedProcessAの処理(ガード) 3 // 本来のprocessBの処理 4 }

投稿2018/01/03 15:53

編集2018/01/03 15:55
Zuishin

総合スコア28656

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/01/05 04:01

回答ありがとうございました。 ガード、という手法は初耳でした。言われてみれば、末尾に書くよりも 先頭に書いたほうが分かりやすいですね……早速、今回のオセロにも取り入れるかもしれません。
guest

0

ベストアンサー

これでいいのでは?

$('li').click(function() { // 選択された箇所のx座標、y座標を取得 var y = getPutY(); var x = getPutX(); if (!isStonePutable(y, x)) { return; } // 選択箇所に自分の石を置く putStone(y, x); // 相手の石をひっくり返す reversibleEnemyStone(); // 手番を交代する turnChange(); }); function isStonePutable(y, x) { // x, yの値が正常であるか検証(getPutX/Y()で異常値が返らないのであれば不要) // x, yに置いたら相手の石をひっくり返せるか確認 }

「x, yに置いたら相手の石をひっくり返せるか確認」はgetReversibleCoordinateを少しいじればいい感じにできるのではと思います。
(あり得る座標を総ざらいして確認していると思いますので、その総ざらいをやめて、座標一つに確認を絞ればよいのではと。)

さて、質問の主題ですが、

// 処理Aを実行する processA(); // プロセスAで実行した内容が正しいかチェックする isCheckedProcessA();

こういう場合、メイン処理とチェック処理は特に理由がないのであれば普通は分けないです。
後で(または他人が)コードを読むときに、行ったり来たりしなければいけないので、面倒です。
分ける理由は、複数のタイミングでチェックを行いたい場合等でしょうか。

特に理由がなければ、processAの処理の節目節目でチェックを行うと思います。
チェックが失敗した時点で後続の処理をキャンセルしたほうが、無駄な処理も減ります。

投稿2018/01/03 15:39

moredeep

総合スコア1507

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/01/05 03:58

個人的に、最も汎用的に使える考え方を詳細に解説いただけたように 感じましたので、今回のベストアンサーとしたいと思います。 回答いただき、本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問