現在、多くの優れた実践、原則 (SOLID、DRY、KISS)、GoF パターンなどがあります。 彼らは皆、開発者である私たちを助けようとしており、優れた、クリーンで、保守しやすく、理解しやすいコードを作成しようとしています。 GRASP は General Responsibility Assignment Software Patterns の略です。 これは、非常に優れた一連の推奨事項、原則、およびパターンであり、コードをより優れたものにする可能性があります。このリストを見てみましょう。 情報専門家 クリエイター コントローラ 低結合 高結束 純粋な製作 間接 保護されたバリエーション ポリモーフィズム 今日、私たちは最初の 2 つの原則を学びます: 情報の専門家と創造者です。 情報エキスパート 情報の専門家は、すべての GRASP パターンの中で最も重要かもしれません。このパターンは、データ (変数、フィールド) を操作するすべてのメソッドが、データ (変数またはフィールド) が存在する同じ場所にある必要があることを示しています。 わかりにくいと思いますので、例を見てみましょう。注文したアイテムの合計を計算する機能を作成したいと考えています。 main.js、OrderList、OrderItem、Product の 4 つのファイルがあるとします。 製品には、ID、名前、および価格 (および、この例とは関係のない他の多くのフィールド) を含めることができます。 class Product { constructor(name, price) { this.name = name; this.price = price; } } OrderItem は、以下のように、product と count を含む単純なオブジェクトになります。 class OrderItem { constructor(product, count) { this.product = product, this.count = count } } OrderList ファイルには、orderItems の配列を操作するためのロジックが含まれます。 class OrderList { constructor(items) { this.items = items; } } そして、main.js は、いくつかの初期ロジックを含むことができ、OrderList をインポートして、このリストで何かを実行できるファイルです。 import { OrderItem } from './OrderItem'; import { OrderList } from './OrderList'; import { Product } from './Product'; const samsung = new Product('Samsung', 200); const apple = new Product('Apple', 300); const lg = new Product('Lg', 150); const samsungOrder = new OrderItem(samsung, 2); const appleOrder = new OrderItem(samsung, 3); const lgOrder = new OrderItem(samsung, 4); const orderList = new OrderList([samsungOrder, appleOrder, lgOrder]); 合計金額を計算するメソッドはどこに作成すればよいですか?少なくとも 2 つのファイルがあり、それぞれをこの目的に使用できますよね?しかし、どの場所が私たちの目標に適しているでしょうか? main.js について考えてみましょう。 次のように書くことができます。 const totalSum = orderList.reduce((res, order) => { return res + order.product.price * order.count }, 0) それが動作します。ただし、orderItem ファイルにはメソッドのないデータが含まれ、orderList ファイルにもメソッドのないデータが含まれ、メイン ファイルには注文アイテムと注文リストを操作するメソッドが含まれます。 よく聞こえません。何らかの形で注文を処理するロジックをさらに追加したい場合、それもメイン ファイルに入れますか?そして、しばらくすると、メイン ファイルには、何千ものコード行に対して、多くの異なるロジックが含まれるようになります。これは非常に悪いことです。このアンチパターンは と呼ばれ、1 つのファイルにすべてが含まれます。 神オブジェクト のアプローチを使用したい場合、どのようにすべきでしょうか?繰り返してみましょう: 情報専門家 データ (変数、フィールド) を操作するすべてのメソッドは、データ (変数またはフィールド) が存在する場所と同じ場所にある必要があります。 つまり、 orderItem には、特定のアイテムの合計を計算できるロジックが含まれている必要があります。 class OrderItem { constructor(product, count) { this.product = product, this.count = count } getTotalPrice() { return this.product.price * this.count; } } orderList には、すべての注文項目の合計を計算できるロジックが含まれている必要があります。 class OrderList { constructor(items) { this.items = items; } getTotalPrice() { return this.items.reduce((res, item) => { return res + item.getTotalPrice(); }, 0); } } また、メイン ファイルはシンプルで、その機能のロジックは含まれません。可能な限りシンプルにします (多くのインポートを除きますが、これはすぐに削除されます)。 そのため、1 つの注文項目のみに関連するロジックは、orderItem に配置する必要があります。 orderItems のセットで何かが相対的に機能している場合は、そのロジックを orderItems に配置する必要があります。 メイン ファイルはエントリ ポイントにすぎません。いくつかの準備とインポートを行い、いくつかのロジックを他のロジックと接続します。 この分離により、コード コンポーネント間の依存関係が少なくなるため、コードの保守性が大幅に向上します。 プロジェクトで常にこの原則を使用できるわけではありませんが、これは非常に優れた原則です。そして、使えるならやるべきです。 クリエイター 前の例では、Main、OrderList、OrderItem、Product の 4 つのファイルがありました。情報の専門家は、メソッドがあるべき場所、つまりデータがある場所と同じ場所にあると言います。 しかし問題は、誰が、どこでオブジェクトを作成すべきかということです。誰が orderList を作成し、だれが orderItem を作成し、だれが Product を作成しますか? 作成者は、各オブジェクト (クラス) は、それが使用される場所でのみ作成する必要があると言います。多くのインポートを含むメイン ファイルの例を覚えていますか?確認しよう: import { OrderItem } from './OrderItem'; import { OrderList } from './OrderList'; import { Product } from './Product'; const samsung = new Product('Samsung', 200); const apple = new Product('Apple', 300); const lg = new Product('Lg', 150); const samsungOrder = new OrderItem(samsung, 2); const appleOrder = new OrderItem(samsung, 3); const lgOrder = new OrderItem(samsung, 4); const orderList = new OrderList([samsungOrder, appleOrder, lgOrder]); const totalSum = orderList.getTotalPrice(); ご覧のとおり、ほとんどすべてのインポートとオブジェクトの作成は main.js にあります。 しかし、実際に誰がどこで使うのかを考えてみましょう。 製品は OrderItem でのみ使用されます。 OrderItem は OrderList でのみ使用されます。 OrderList は Main で使用されます。次のようになります。 Main → OrderList → OrderItem → Prodcut しかし、Main が OrderList のみを使用する場合、Main で OrderItem を作成するのはなぜでしょうか?ここで製品も作成するのはなぜですか?この時点で、Main.js はほとんどすべてを作成 (およびインポート) します。これは悪いです。 の原則に従って、オブジェクトが使用される場所でのみオブジェクトを作成する必要があります。アプリを使用して商品をカートに追加したとします。これは次のようになります。 創造主 Main.js: ここでは OrderList のみを作成 (およびインポート) します。 import { OrderList } from './OrderList'; const cartProducts = [{ name: 'Samsung', price: 200, count: 2 }, { name: 'Apple', price: 300, count: 3 }, {name: 'Lg', price: 150, count: 4 }]; const orderList = new OrderList(cartProducts); const totalPrice = orderList.getTotalPrice(); OrderList.js: ここでは OrderItem のみを作成 (およびインポート) します。 import { OrderItem } from './OrderItem'; class OrderList { constructor(items) { this.items = items.map(item => new OrderItem(item)); } getTotalPrice() { return this.items.reduce((res, item) => { return res + item.getPrice(); }, 0); } } OrderItem.js: ここでは Product のみを作成 (およびインポート) します。 import { Product } from './Product'; class OrderItem { constructor(item) { this.product = new Product(item.name, item.price); this.count = item.count; } } Product.js: class Product { constructor(name, price) { this.name = name; this.price = price; } } 単純な依存関係があります。 Main → OrderList → OrderItem → Product そして今、各オブジェクトは、それが使用されるその場所でのみ作成されます。それが の原理が言っていることです。 創造主 この紹介が皆さんのお役に立てば幸いです の次のシリーズでは、他の原則について説明します。 。GRASP Unsplashの による写真 Gabriel Heinzer