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

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

新規登録して質問してみよう
ただいま回答率
85.47%
JavaScript

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

意見交換

8回答

1040閲覧

クラス化すべきかどうか?勘所がつかめません

munekun

総合スコア39

JavaScript

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

1グッド

1クリップ

投稿2024/04/09 18:05

編集2024/04/09 18:09

テーマ、知りたいこと

JavaScriptでクラス化すべきかどうか悩んでいます。

文末にある「対処案:モジュールのまま」か「対処案:クラス化する」について、どちらにすべきか(どちらにどういう利点があり、どういうケースで優先すべきか)ご意見いただけましたら幸いです。

背景、状況

以下のように、あるエリアについて「色々な処理のファイル」と「HTMLテンプレートのファイル」というペア構成でモジュールファイルを作りました。エリアを超えて類似処理がある場合にクラス化すべきかどうかが判断できない状況です。

エリア色々な処理のファイルHTMLテンプレートのファイル
.xxx-areaxxxAreaManager.jsxxxAreaHtml.js

コードは以下のような感じです。(最低限のイメージを伝えるためのもので実際は数百行ありますが、それぞれの処理を詳細にお読みいただく必要はないかと思います。)

JavaScript

1/* 2 このファイル名は xxxAreaManager.js です 3 .xxx-area エリアについての色々な処理が書かれています 4*/ 5 6// 各種 import 7import util from '/assets/js/area/utiljs'; 8import xxxAreaSearchConditions from '/assets/js/area/xxxAreaSearchConditions.js'; 9import xxxAreaHtml from '/assets/js/area/xxxAreaHtml.js'; 10 11// エリア名 12const areaName = 'xxx-area'; 13 14// エリア表示 15function setAreaHtml(){ 16 document.quertySelector('.target') 17 .insertAdjacentHTML('afterbegin', xxxAreaHtml.areaHtml()); 18} 19 20// ソートメニュー表示切替 21function toggleDisplaySortMenu(){ 22 document.quertySelector('.sort-menu') 23 .classList.toggle('is-hide'); 24} 25 26// Ajax でアイテムを取得し HTML を作りセット 27async function fetchItemsAndSetHtml(){ 28 const queryString = xxxAreaSearchConditions.generateQueryString(); 29 const response = await util.getAjax('/item/get?' + queryString ); 30 document.quertySelector('.items') 31 .insertAdjacentHTML('afterbegin', xxxAreaHtml.itemsHtml(response.items)); 32} 33 34export default { setAreaHtml, toggleDisplaySortMenu, fetchItemsAndSetHtml }

JavaScript

1/* 2 このファイル名は xxxAreaHtml.js です 3 .xxx-area エリアのHTMLテンプレートが書かれています 4*/ 5 6// 各種 import 7import util from '/assets/js/area/util.js'; 8import utilHtml from '/assets/js/area/utilHtml.js'; 9 10// エリア名 11const areaName = 'xxx-area'; 12 13// エリアのHTMLテンプレート 14function areaHtml(){ 15 return ` 16 <div class="${areaName}"> 17 ${sortMenuHtml()} 18 <div class="others">${utilHtml.esc('その他いろいろ')}</div> 19 </div>`; 20} 21 22// ソートメニューのHTMLテンプレート 23function sortMenuHtml(){ 24 return `<ul class="sort-menu"></ul>`; 25} 26 27// アイテムのHTMLテンプレート 28function itemsHtml(items) { 29 return items.map(item => `<div>${utilHtml.esc(item.name)}</div>`).join(''); 30} 31 32export default { areaHtml, itemsHtml }

そしてこのようなエリアごとのペアが大量にあります。(各ファイル名をきちんと一読される必要はありません。ざっくり.main-xxx-area系と.library-xxx-area系があります。)

エリア色々な処理のファイルHTMLテンプレートのファイル
.main-books-areamainBooksAreaManager.jsmainBooksAreaHtml.js
.main-users-areamainUsersAreaManager.jsmainUsersAreaHtml.js
.main-recommend-books-areamainRecommondBooksAreaManager.jsmainRecommondBooksAreaHtml.js
.library-books-arealibraryBooksAreaManager.jslibraryBooksAreaHtml.js
.library-followers-arealibraryFollowersAreaManager.jslibraryFollowersAreaHtml.js

などなど・・

質問

しかし、いくつかのファイルにはかなり類似の関数が見られます。

例えばsortMenuHtml()について、mainBooksAreaHtml.js では「人気順と作成順」ですし、

JavaScript

1function sortMenuHtml(){ 2 return ` 3 <ul class="sort-menu"> 4 <li>人気順</li><li>作成順</li> 5 </ul>`; 6}

また libraryBooksAreaHtml.js では「更新順と作成順」といった感じです。

JavaScript

1function sortMenuHtml(){ 2 return ` 3 <ul class="sort-menu"> 4 <li>更新順</li><li>作成順</li> 5 </ul>`; 6}

そこで共通処理を担う上位ファイルが必要だろうとなったのですが、モジュールのままで上位ファイルを作るか、すべてクラス化し継承関係を持たせるべきか、というのが全くわかりません。

対処案:モジュールのまま

クラス化しなければ上位ファイル commonAreaManager.js と commonAreaHtml.js などを作り、例えば上のようなメニュー関数ならこのように書くかと思います。

JavaScript

1/* 2 このファイル名は commonAreaHtml.js です 3 各エリアで共通するHTMLテンプレートが書かれています 4*/ 5 6function sortMenuHtml(areaName){ 7 if (areaName === 'main-books-area') { 8 return ` 9 <ul class="sort-menu"> 10 <li>人気順</li><li>作成順</li> 11 </ul>`; 12 } else if (areaName === 'library-books-area') { 13 return ` 14 <ul class="sort-menu"> 15 <li>更新順</li><li>作成順</li> 16 </ul>`; 17 } 18} 19 20export { sortMenuHtml }

しかしこの対処案では、「この commonAreaHtml.js は各エリアの上位ファイルなのか?それとも .main-books-area などと同じように .common-area というエリアがサイトにあるのか?」というのが分かりにくく、(コメントを見れば済む話ですが)この点がいまいちだと思います。

対処案:クラス化する

一方でクラス化すると以下のconstructorでのthrowによって、「これは必ず抽象クラスであって.common-area というエリアがサイトにあるわけではない」ということが強制できる点が良さそうだと思いました。

JavaScript

1/* 2 このファイル名は CommonAreaHtml.js です 3 各エリアで共通するHTMLテンプレートが書かれています 4*/ 5 6export default class CommonAreaHtml 7{ 8 constructor(areaName) { 9 this.areaName = areaName; 10 11 if (new.target === CommonAreaHtml) { 12 throw new TypeError("Cannot instantiate abstract class"); 13 } 14 } 15 16 sortMenuHtml(){ 17 if (this.areaName === 'main-books-area') { 18 // 同上 19 } else if (this.areaName === 'library-books-area') { 20 // 同上 21 } 22 } 23}

そして各エリアのファイルも以下のようにCommonAreaHtmlを継承した上でクラス化し、モジュールではconst areaName = ''と宣言していたものをsuper('')と宣言します。

JavaScript

1/* 2 このファイル名は MainBooksAreaHtml.js です 3 .main-books-area エリアのHTMLテンプレートが書かれています 4*/ 5 6export default class MainBooksAreaHtml extends CommonAreaHtml 7{ 8 constructor() { 9 super('main-books-area'); 10 } 11 12 // 略 13}

しかしクラスをこういう使い方していいのかなという疑念があります。クラスというのは「なんからの状態を持たせ、処理の過程でそれが変わっていくようなケースで用いるものだ」という理解をしているためです。

今回のようにただHTMLテンプレートを返すだけとか、単発的な処理を行うだけのケースにすぎないのに、抽象クラスであることの明示と強制という目的で用いていいのだろうか?という疑念です。

まとめ

ここまでお読みいただきありがとうございます。
以上のように「対処案:モジュールのまま」か「対処案:クラス化する」について、どちらにすべきかという判断ができない状況です。

この点のアドバイスはもちろん、「そもそも全体的な設計がおかしい」など根本的なご指摘も大募集です。

なるべく必要最低限にと思いコードは各所で割愛しておりますが、これだけでは判断がつかないだとか、情報の不足などございましたらご指摘ください。

よろしくお願い致します。

ams2020👍を押しています

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

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

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

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

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

回答8

#1

hentaiman

総合スコア6422

投稿2024/04/10 00:01

説明はさておきクラス化するよりは共通モジュール化した方が良いですが、共通モジュール化するよりも現状のままが良いです。

しかしながら

なんからの状態を持たせ、処理の過程でそれが変わっていくようなケースで用いるものだ

これを理解した上であえてクラスを用いた作りにしたいと言うのならそれも良いと思います。
WEBで質問しているという事は身近にあなたより詳しい人がいないという事でしょうから、現状の環境で最も知識のあるあなたが適切だと思うように作れば良いのです。

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

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

#2

m.ts10806

総合スコア80852

投稿2024/04/10 00:32

若干横道・遠回りを許容するのであれば、JavaやC#などの「そもそもクラス中心に組み立てられている言語」を勉強するのも1つ手としてありだと思います。クラス作ってmainメソッド置かないと動かないですから。
役割分担とかオブジェクト指向の概念も学べるのでより広い考え方やモノの見方も身につくと思うので、今後の役にも立つと思います。

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

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

#3

munekun

総合スコア39

投稿2024/04/10 14:18

編集2024/04/10 14:58

#1 hentaiman様
仰る通り独学の趣味グラマで、周りにこういった知人もおらず辛いところです。
アドバイス誠にありがとうございます。
クラスについて hentaiman様 と同じ理解を私ができているか不安ですが、ひとまず仰るように現状まま、個々のモジュールに任せるという方針で進めてみます。

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

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

#4

munekun

総合スコア39

投稿2024/04/10 14:21

#2 m.ts10806様
そうですね、締め切りがあるわけでもないので、まったり進むのもアリです。
「クラス作ってmainメソッド置かないと動かない」なんていうという前提に基づく言語があったとは意外でした!
広く知るほどに方針が適切に定まりそうですね。ありがとうございます。

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

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

#5

hentaiman

総合スコア6422

投稿2024/04/14 10:37

趣味ならあえて共通モジュール化を試してみるのも良いかもしれません。共通化する事にも当然メリットデメリットはあります。

質問内容に関わらずどのような設計方針でも特定の状況下ではメリットの方が大きくなり、特定の状況下ではデメリットが大きくなるものです。
たとえば中央銀行の金庫にとっては鍵認証指紋認証虹彩認証など複数の厳しい認証を兼ねる事で堅牢さを得られそれはメリットになりますが、そこら辺の荷物の集配に使う一時的な倉庫ではそれは時間もコストも掛かる為デメリットになります。
分からないうちは試して実感するのも必要な事だと思います。

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

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

#6

standard-soft

総合スコア197

投稿2024/04/16 07:02

「そもそも全体的な設計がおかしい」という視点でみると、

現代的なプログラミングでは、継承は全てバッドパターンなので
将来的に苦しくなると思いますので、やめておいた方がよいです。

継承を廃止した言語が増えてきているのも、継承は使う必要がないという判断からですね。

特にJavaScriptは、柔軟なプログラミング言語ですのでクラスが必要な場面はないです。

>しかしこの対処案では、「この commonAreaHtml.js は各エリアの上位ファイルなのか?それとも .main-books-area などと同じように .common-area というエリアがサイトにあるのか?」というのが分かりにくく

命名の問題だけなので、命名を工夫するとよいでしょう。
commonFuncAreaHtml.js とか?ですかね。

あと、[CcmmonAreaHtml]を上位の抽象クラスにして実装したりすると
あとから common というものをAreaで登録したくなったときにハマるので
これもやめておいたほうがいいです。

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

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

#7

munekun

総合スコア39

投稿2024/04/19 08:07

#5 hentaiman様
すみません。遅くなりました。たしかにやる前から判断するのはダメですね。
とりあえず試してみて、私のケースにおけるメリットデメリットを把握してみます。
たびたびのアドバイス誠にありがとうございます。

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

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

#8

munekun

総合スコア39

投稿2024/04/19 08:10

#6 standard-soft様
継承は全てバッドパターン!?驚きです。phpなんてクラスの継承しまくりで書いてしまいました。(それともお話はJavaScriptだけのことでphpはいいのかしら)

うまい命名も大事なテクニックの一つだと改めて確認できました。
ありがとうございます。

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

この意見交換はまだ受付中です。

会員登録して回答してみよう

アカウントをお持ちの方は

関連した質問