複合デザインパターン

Feb 04 2023
やあ、みんな!!!!現在のコードベースでは、数多くのデザインパターンが使用されていますが、今回はその中の 1 つである「コンポジット」を把握してみました。はじめに よく知られた構造設計パターンの 1 つは複合材です。

やあ、みんな!!!!

現在のコードベースでは、数多くのデザインパターンが使用されていますが、今回はその中の 1 つである「コンポジット」を把握してみました。

序章

よく知られている構造設計パターンの 1 つは複合材です。単一のインターフェイスを使用してオブジェクトを作成します。これは、ポリモーフィズムと、すべて共通のインターフェイスを持つ個別のノードまたは小さなコンポーネントで構成されるツリー構造を広範囲に使用します。小さなコンポーネントからより洗練された構造を簡単に構築できます。

プラガブル デザイン パターンには、複合パターンも含まれます。

図 — 構造

コードのスニペット

コア要素

コンポーネント:ツリー内の各ノードが採用する標準インターフェイス。

プリミティブ(リーフ):自律アイテムであり、子孫を持ちません。

コンポジット:複数のリーフ コンポーネントのコンテナーです。

ケーススタディで状況を簡単に確認してみましょう。

プロジェクトの初日: ファイルを Google ドライブにアップロードする機能など、簡単な機能やモジュールを備えたプロジェクトに取り組んでいるとします。

非常に簡単なシナリオなので、以下のコードを確認してください。

struct File {
    var name: String
    var data: Data
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        /// Problem On Day 1
        func finishedCreateFileProcess(file: File) {
            uploadToGoogleDrive(file: File(name: "test", data: Data()))
        }
        
        func uploadToGoogleDrive(file: File) {
            // Code to upload to Google Drive.
        }
    }
}

こんにちは、開発者 多くのクライアントが、ファイルのアップロード手順を変更したいと考えています。Google Drive および Amazon S3 オプションでは、アップロード プロセスが必要です。

開発者はクライアントに問題はないと保証しました。できる限り早くお知らせいたします。

Xcode のコードを数行変更するだけです。スムーズに動きます。

struct File {
    var name: String
    var data: Data
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        /// Two Weeks Later
        func finishedCreateFileProcess(file: File, shouldUploadToGD: Bool) {
            if shouldUploadToGD {
                uploadToGoogleDrive(file: File(name: "test", data: Data()))
            } else {
                uploadToAmazons3(file: File(name: "test", data: Data()))
            }
        }
        
        func uploadToGoogleDrive(file: File) {
            // Code to upload to Google Drive.
        }
        
        func uploadToAmazons3(file: File) {
            // Code to upload to Amazon S3
        }
    }
}

ただし、話はここで終わりません。2 週間以上後、クライアントは戻ってきて、Dropbox などのさらなるストレージ代替手段を含めるよう要求しました。

そして、開発者が今回どのように反応するかは誰もがよく知っています。開発者たちは、これが作業に着手する前の最後の変更になると今でも考えています。

Xcode でコードを作成し、テストします。

struct File {
    var name: String
    var data: Data
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        /// Four Weeks Later
        enum StorageService: Int {
            case googleDrive = 0
            case amazonS3
            case dropbox
        }
        
        func finishedCreateFileProcess(file: File, uploadTo service: StorageService) {
            switch service {
            case .googleDrive:
                uploadToGoogleDrive(file: File(name: "test", data: Data()))
            case .amazonS3:
                uploadToAmazons3(file: File(name: "test", data: Data()))
            case .dropbox:
                uploadToDropBox(file: File(name: "test", data: Data()))
            }
        }
        
        func uploadToGoogleDrive(file: File) {
            // Code to upload to Google Drive.
        }
        
        func uploadToAmazons3(file: File) {
            // Code to upload to Amazon S3
        }
        
        func uploadToDropBox(file: File) {
            // Code to upload to DropBox
        }
    }
}

毎回、開発者はオープンクローズ原則に違反しており、これは開発プロセスに悪影響を及ぼすことに注意してください。

またしても、クライアントには新たな要求があり、今回、開発者は複合から始める前に、適切なパターンを使用して完全に再構築することを選択しました。

//
//  UseCase1.swift
//  CompositeDesignPattern
//
//  Created by Nikunj Modi on 30/01/23.
//

import Foundation

protocol StorageService {
    func upload()
}

class GoogleDriveStorage: StorageService {
    func upload() {
        // Here is the need to implement business logic.
        print("GoogleDriveStorage")
    }
}

class DropBoxStorage: StorageService {
    func upload() {
        // Here is the need to implement business logic.
        print("DropBoxStorage")
    }
}

class AmazonS3Storage: StorageService {
    func upload() {
        // Here is the need to implement business logic.
        print("AmazonS3Storage")
    }
}

class StorageComposite: StorageService {
    let service: [StorageService]
    
    init(services: [StorageService]) {
        self.service = services
    }
    
    func upload() {
        print("StorageComposite")
        for service in service {
            service.upload()
        }
    }
}

class ExampleViewModel {
    let service: StorageService
    
    init(service: StorageService) {
        self.service = service
    }
    
    func finishedCreatingFile(file: File) {
        self.service.upload()
    }
}
struct File {
    var name: String
    var data: Data
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let vm = ExampleViewModel(service: StorageComposite(services: [
            GoogleDriveStorage(),
            AmazonS3Storage(),
            DropBoxStorage()
        ]))
        vm.finishedCreatingFile(file: File(name: "test", data: Data()))
    }
}

https://theniks.github.io/Portfolio/

ご質問やご意見がございましたら、以下に投稿してください。ぜひご連絡をお待ちしております。