Go言語における10種のデザインパターンの実装とインターネットシナリオでの応用
1. シングルトンパターン
パターン定義
グローバルにクラスのインスタンスが1つのみ作成されるようにし、統一されたアクセスポイントを提供する。これは生成系パターンに属し、グローバルなユニークな制御が必要なシナリオに適している。
核心機能
- ユニークなインスタンス:グローバルに1つのオブジェクトインスタンスのみ存在する。
- 自己初期化:クラス自体がインスタンスの作成を担当する。
- グローバルアクセス:静的メソッドまたはグローバル変数を通じてアクセスエントリを提供する。
利点と欠点
利点 | 欠点 |
---|---|
リソース/状態のグローバルなユニーク性を保証する | 高結合の原則に抵触し、モジュールの結合度が高くなる |
リソースの重複した作成を減らす | ユニットテストの分離が難しい |
便利なグローバルアクセスポイントを提供する | 依存性注入パターンを損なう |
シナリオ応用
- マイクロサービス構成センター(例えばSpring Cloud Configの代替):分散システムの構成を一括管理する。
- データベース接続プール(例えばPostgreSQL/MySQLの接続管理):同時接続数を制御する。
- 分散ログサービス(例えばELK Stackのログコレクタ):ログハンドラの重複した作成を避ける。
- APIレート制限器(例えばStripe APIのリクエスト頻度制御):レート制限状態をグローバルで共有する。
Go言語による実装(並列処理安全なバージョン)
package singleton
import (
"sync"
)
// ConfigManager シングルトン構造体、構成管理をシミュレート
type ConfigManager struct {
AppConfig map[string]string
}
var (
once sync.Once
instance *ConfigManager
)
// GetInstance グローバルアクセスポイント、sync.Onceを使って並列処理の安全性を保証
func GetInstance() *ConfigManager {
once.Do(func() {
instance = &ConfigManager{
AppConfig: map[string]string{
"env": "prod",
"port": "8080",
"timeout": "30s",
},
}
})
return instance
}
// 並列処理テストの例
func TestConcurrency() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
config := GetInstance()
println(config.AppConfig["env"])
}()
}
wg.Wait()
}
2. ファクトリパターン
パターン定義
オブジェクトの作成ロジックをカプセル化し、サブクラスを通じてインスタンス化する具体的な製品を決定する。これは生成系パターンに属し、オブジェクトの作成と使用を切り離す。
核心機能
- 作成ロジックのカプセル化:クライアントは具体的な作成詳細を知る必要がない。
- ポリモーフィズムのサポート:インターフェイスを通じて製品ファミリーを拡張する。
- 開放・閉鎖原則:新しい製品を追加しても既存のコードを修正する必要がない。
利点と欠点
利点 | 欠点 |
---|---|
オブジェクトの作成と使用を分離する | クラスの数が増える(各製品に対応するファクトリが必要) |
新しい製品を拡張しやすい | ファクトリクラスが複雑になりすぎる可能性がある |
依存性逆転原則に準拠する | クライアントは製品の抽象インターフェイスを知る必要がある |
シナリオ応用
- 決済ゲートウェイ統合(Stripe/PayPal/Apple Pay):決済方法に応じて異なるプロセッサを作成する。
- クラウドストレージクライアント(S3/GCS/Azure Blob):ストレージサービスに応じて対応するAPIクライアントを作成する。
- メッセージキューアダプタ(Kafka/RabbitMQ/NATS):メッセージ送信インターフェイスの作成ロジックを統一する。
- サードパーティログインサービス(OAuth2/OpenID Connect):異なるプラットフォームに対する認証クライアントを動的に生成する。
Go言語による実装(抽象ファクトリパターン)
package factory
import "fmt"
// PaymentProcessor 決済プロセッサインターフェイス
type PaymentProcessor interface {
Process(amount float64) string
}
// StripeProcessor Stripe決済の実装
type StripeProcessor struct{}
func (s *StripeProcessor) Process(amount float64) string {
return fmt.Sprintf("Stripe processed $%.2f", amount)
}
// PayPalProcessor PayPal決済の実装
type PayPalProcessor struct{}
func (p *PayPalProcessor) Process(amount float64) string {
return fmt.Sprintf("PayPal processed $%.2f", amount)
}
// PaymentFactory ファクトリインターフェイス
type PaymentFactory interface {
CreateProcessor() PaymentProcessor
}
// StripeFactory Stripeファクトリの実装
type StripeFactory struct{}
func (s *StripeFactory) CreateProcessor() PaymentProcessor {
return &StripeProcessor{}
}
// PayPalFactory PayPalファクトリの実装
type PayPalFactory struct{}
func (p *PayPalFactory) CreateProcessor() PaymentProcessor {
return &PayPalProcessor{}
}
// クライアントの使用例
func NewPaymentClient(factory PaymentFactory) PaymentProcessor {
return factory.CreateProcessor()
}
3. オブザーバーパターン
パターン定義
オブジェクト間に1対多の依存関係を定義し、被観測者の状態が変更されたときに自動的にすべての観測者に通知する。これは振る舞い系パターンに属し、イベント駆動型のシナリオに適している。
核心機能
- イベント駆動:被観測者の状態の変更が観測者の更新をトリガする。
- 緩和された結合:被観測者と観測者は抽象インターフェイスを通じてのみ相互作用する。
- 動的なサブスクリプション:観測者はいつでも登録または解除できる。
利点と欠点
利点 | 欠点 |
---|---|
ブロードキャスト方式のイベント通知をサポートする | 多数の観測者が存在するとパフォーマンス問題を引き起こす可能性がある |
新しい観測者の種類を拡張しやすい | 循環参照がメモリリークを引き起こす可能性がある |
開放・閉鎖原則に準拠する | 被観測者は観測者のリストを維持する必要がある |
シナリオ応用
- リアルタイム通知システム(Slackチャンネルの更新/Zoom会議のリマインダー):ユーザーが被観測者にサブスクライブしてリアルタイム通知を受け取る。
- 株価情報プラットフォーム(Robinhood/Nasdaqのリアルタイム株価):投資家が株コードにサブスクライブして価格の変動を得る。
- ECサイトの在庫監視(Amazonの商品入荷通知):ユーザーが商品にサブスクライブして在庫の変動を知らせる。
- 分散システム監視(Datadogのメトリックアラーム):監視サービスがマイクロサービスの状態変化にサブスクライブする。
Go言語による実装(イベント駆動型モデル)
package observer
import "fmt"
// Observer オブザーバーインターフェイス
type Observer interface {
Update(message string)
}
// Subject 被観測者インターフェイス
type Subject interface {
Attach(observer Observer)
Detach(observer Observer)
Notify(message string)
}
// StockTicker 具体的な被観測者:株価情報
type StockTicker struct {
observers []Observer
symbol string
price float64
}
func (s *StockTicker) Attach(observer Observer) {
s.observers = append(s.observers, observer)
}
func (s *StockTicker) Detach(observer Observer) {
for i, o := range s.observers {
if o == observer {
s.observers = append(s.observers[:i], s.observers[i+1:]...)
return
}
}
}
func (s *StockTicker) Notify(message string) {
for _, o := range s.observers {
o.Update(message)
}
}
// Investor 具体的な観測者:投資家
type Investor struct {
name string
}
func (i *Investor) Update(message string) {
fmt.Printf("%s received: %s\n", i.name, message)
}
4. デコレータパターン
パターン定義
オブジェクトに動的に新しい機能を追加し、継承ではなく合成を通じてその責務を拡張する。これは構造系パターンに属し、機能の階層化が必要なシナリオに適している。
核心機能
- 透明な拡張:インターフェイスを一貫性を保ち、クライアントはそれに気付かない。
- 合成の特徴:複数層のデコレータのネストをサポートする。
- 実行時バインディング:オブジェクトの機能の組み合わせを動的に決定する。
利点と欠点
利点 | 欠点 |
---|---|
継承階層の爆発を避ける | 複数層のデコレータがあるとデバッグが難しくなる可能性がある |
機能の自由な組み合わせをサポートする | 過剰な使用はシステムの複雑さを増やす |
開放・閉鎖原則に準拠する | デコレーションの順序が実行結果に影響を与える可能性がある |
シナリオ応用
- APIミドルウェア(Express.js/Koa.jsのミドルウェアシステム):ログ記録、認証、レート制限などの機能を積み重ねる。
- ECサイトの注文処理(送料計算/割引オファー/税金処理):注文合計金額を段階的に計算する。
- クラウドストレージサービス(S3の暗号化/圧縮/CDNアクセラレーション):ストレージ機能を動的に組み合わせる。
- マイクロサービスゲートウェイ(Kong/NginXのプラグインシステム):リクエストの検証、レスポンスの変換、トラフィックモニタリング。
Go言語による実装(HTTPミドルウェアのシミュレーション)
package decorator
import "fmt"
// Handler 基本的な処理関数
type Handler func(request string) string
// LogDecorator ログデコレータ
func LogDecorator(next Handler) Handler {
return func(request string) string {
fmt.Printf("Received request: %s\n", request)
return next(request)
}
}
// AuthDecorator 認証デコレータ
func AuthDecorator(next Handler) Handler {
return func(request string) string {
if request != "authenticated" {
return "Unauthorized"
}
return next(request)
}
}
// 基本的な処理関数
func BasicHandler(request string) string {
return fmt.Sprintf("Processed: %s", request)
}
// 複合デコレータの例
func CompositeHandler() Handler {
return LogDecorator(AuthDecorator(BasicHandler))
}
5. ストラテジーパターン
パターン定義
アルゴリズムを独立したストラテジークラスにカプセル化し、実行時に動的に切り替えることをサポートする。これは振る舞い系パターンに属し、複数のアルゴリズムが存在するシナリオに適している。
核心機能
- アルゴリズムのカプセル化:各ストラテジーが独立してアルゴリズムを実装する。
- ストラテジーの切り替え:実行時に動的にストラテジーを選択する。
- 開放・閉鎖原則:新しいストラテジーを追加しても既存のコードを修正する必要がない。
利点と欠点
利点 | 欠点 |
---|---|
アルゴリズムをクライアントから切り離す | クライアントはすべてのストラテジーの種類を知る必要がある |
アルゴリズムの拡張と置き換えを容易にする | ストラテジークラスの数が急速に増える可能性がある |
複合ストラテジーをサポートする | ストラテジー間で状態を共有することが難しい |
シナリオ応用
- ECサイトのプロモーションエンジン(全額割引/割引/ギフトのストラテジー):活動の種類に応じて動的に計算ロジックを切り替える。
- 物流配送システム(FedEx/UPS/USPSの配送ストラテジー):ユーザーの選択に応じて配送料を計算する。
- データソートサービス(価格/売上高/評価でソート):フロントエンドのリクエストがソートストラテジーを決定する。
- 広告配置アルゴリズム(精密マーケティング/地理的ターゲティング/頻度制御):配置ストラテジーをリアルタイムで調整する。
Go言語による実装(ECサイトのプロモーション計算)
package strategy
import "fmt"
// PromotionStrategy プロモーションストラテジーインターフェイス
type PromotionStrategy interface {
Calculate(amount float64) float64
}
// PercentDiscount 割合割引ストラテジー
type PercentDiscount struct {
rate float64 // 割引率(0.1 = 10%)
}
func (p *PercentDiscount) Calculate(amount float64) float64 {
return amount * (1 - p.rate)
}
// FixedDiscount 固定額割引ストラテジー
type FixedDiscount struct {
offset float64 // 固定減額額
}
func (f *FixedDiscount) Calculate(amount float64) float64 {
if amount > f.offset {
return amount - f.offset
}
return amount
}
// CheckoutContext チェックアウトコンテキスト
type CheckoutContext struct {
strategy PromotionStrategy
}
func (c *CheckoutContext) SetStrategy(strategy PromotionStrategy) {
c.strategy = strategy
}
func (c *CheckoutContext) CalculateFinalAmount(amount float64) float64 {
return c.strategy.Calculate(amount)
}
6. アダプターパターン
パターン定義
互換性のないインターフェイスを変換し、異なるインターフェイスを持つクラスが一緒に動作できるようにする。これは構造系パターンに属し、システム統合のシナリオに適している。
核心機能
- インターフェイスの変換:元のインターフェイスをターゲットインターフェイスに適合させる。
- システムの切り離し:クライアントと被適応クラスは直接相互作用する必要がない。
- 互換性:元のシステムコードを維持し、アダプター層を追加する。
利点と欠点
利点 | 欠点 |
---|---|
インターフェイスの互換性の問題を解決する | システムの抽象層の複雑さが増す |
既存システムのコードを再利用できる | 過剰な使用はシステムの保守が難しくなる可能性がある |
双方向の適応をサポートする | パフォーマンスのオーバーヘッドが発生する可能性がある |
シナリオ応用
- 既存システムの移行(COBOLシステムをマイクロサービスアーキテクチャと連携する):古いシステムのAPIを適合させる。
- サードパーティライブラリの統合(MongoDBドライバーをSQLインターフェイスに適合させる):データアクセス層を統一する。
- クロスプラットフォーム開発(iOS/AndroidのネイティブAPIを統一されたインターフェイスに適合させる):モバイルアプリケーションフレームワーク。
- クラウドサービスの連携(AWS SQSをKafkaのメッセージ形式に適合させる):ハイブリッドクラウドアーキテクチャ。
Go言語による実装(サードパーティ決済の適合)
package adapter
import (
"errors"
"fmt"
)
// ThirdPartyPayment サードパーティ決済インターフェイス(元のインターフェイス)
type ThirdPartyPayment interface {
ProcessPayment(orderID string, amount float64) error
}
// LegacyPayPal 旧版PayPalの実装(元の実装)
type LegacyPayPal struct{}
func (p *LegacyPayPal) ProcessPayment(orderID string, amount float64) error {
fmt.Printf("Legacy PayPal processing order %s for $%.2f\n", orderID, amount)
return nil
}
// TargetPayment ターゲット決済インターフェイス(統一されたインターフェイス)
type TargetPayment interface {
Pay(orderID string, amountUSD float64) error
}
// PayPalAdapter アダプターの実装
type PayPalAdapter struct {
legacy *LegacyPayPal
}
func (a *PayPalAdapter) Pay(orderID string, amountUSD float64) error {
// ターゲットインターフェイスを元のインターフェイスのパラメータに変換
return a.legacy.ProcessPayment(orderID, amountUSD)
}
// 互換性のない状況を処理する例
func HandleIncompatiblePayment(payment ThirdPartyPayment) TargetPayment {
return &PayPalAdapter{legacy: payment.(*LegacyPayPal)}
}
7. プロキシパターン
パターン定義
ターゲットオブジェクトに対してプロキシ層を提供し、そのアクセスを制御する。これは構造系パターンに属し、遠隔アクセスやアクセス制御などのシナリオに適している。
核心機能
- アクセス制御:プロキシ層がリクエストを截获して処理する。
- レイジーロード:必要に応じてターゲットオブジェクトを作成する。
- 責務の分離:プロキシが非ビジネスロジック(ログ記録/セキュリティ/キャッシュ)を処理する。
利点と欠点
利点 | 欠点 |
---|---|
ターゲットオブジェクトを保護する | リクエスト処理の遅延が増える |
分散アクセスをサポートする | プロキシ層が単一障害点になる可能性がある |
レイジーロードを実装できる | プロキシクラスとターゲットクラスのインターフェイスが一致する必要がある |
シナリオ応用
- APIゲートウェイ(Apigee/PostmanのAPI管理):バックエンドのマイクロサービスをプロキシ化し、統一されたエントリポイントを提供する。
- キャッシュプロキシ(Redis/Memcachedのキャッシュ層):データベースのクエリ結果をキャッシュする。
- アクセス制御プロキシ(OAuth2の認可サーバー):リクエストを截获し、ユーザーのアクセス権を検証する。
- 遠隔プロキシ(gRPCの遠隔サービス呼び出し):ネットワーク通信の詳細を隠す。
Go言語による実装(キャッシュプロキシ)
package proxy
import (
"sync"
"time"
)
// RealData 実データオブジェクト(データベースクエリ)
type RealData struct {
ID string
Content string
LastUpdate time.Time
}
func (r *RealData) FetchData() string {
// データベースクエリの遅延をシミュレート
time.Sleep(500 * time.Millisecond)
return r.Content
}
// CacheProxy キャッシュプロキシ
type CacheProxy struct {
realData *RealData
cache map[string]string
mu sync.Mutex
}
func NewCacheProxy(id string, content string) *CacheProxy {
return &CacheProxy{
realData: &RealData{ID: id, Content: content, LastUpdate: time.Now()},
cache: make(map[string]string),
}
}
func (c *CacheProxy) FetchData() string {
c.mu.Lock()
defer c.mu.Unlock()
if data, exists := c.cache[c.realData.ID]; exists {
return data // キャッシュされたデータを直接返す
}
// 初回アクセス、実データを取得してキャッシュする
data := c.realData.FetchData()
c.cache[c.realData.ID] = data
return data
}
8. コマンドパターン
パターン定義
リクエストをコマンドオブジェクトにカプセル化し、リクエストの送信者と受信者を切り離す。これは振る舞い系パターンに属し、元に戻しやログ記録をサポートするシナリオに適している。
核心機能
- リクエストのカプセル化:コマンドオブジェクトには実行に必要なすべての情報が含まれる。
- トランザクションのサポート:一括実行とロールバックをサポートする。
- ログ記録:コマンドの実行履歴を永続化できる。
利点と欠点
利点 | 欠点 |
---|---|
元に戻し/やり直し操作をサポートする | コマンドクラスの数が大幅に増える可能性がある |
リクエストの送信と受信を切り離す | 複雑なコマンドロジックは保守が難しい |
一括処理をサポートする | コマンドのパラメータは事前に決定する必要がある |
シナリオ応用
- バージョン管理システム(Gitのコミット操作):各コミットをロールバック可能なコマンドとして扱うことができる。
- データベーストランザクション(ACID操作のカプセル化):複数のSQLコマンドを組み合わせてコミット/ロールバックをサポートする。
- タスクスケジューリングシステム(Airflowのタスクオーケストレーション):分散タスクを実行可能なコマンドにカプセル化する。
- テキストエディタ(元に戻し/やり直し機能):編集操作をコマンドオブジェクトとして記録する。
Go言語による実装(データベーストランザクションのシミュレーション)
package command
import (
"database/sql"
"fmt"
)
// DatabaseReceiver データベース受信者
type DatabaseReceiver struct {
db *sql.DB
}
// シミュレートSQL実行
func (r *DatabaseReceiver) ExecuteSQL(sqlStmt string) error {
fmt.Printf("Executing: %s\n", sqlStmt)
return nil
}
func (r *DatabaseReceiver) Rollback() error {
fmt.Println("Rolling back transaction")
return nil // シミュレートロールバック
}
// Command コマンドインターフェイス
type Command interface {
Execute() error
Undo() error
}
// InsertCommand 挿入コマンド
type InsertCommand struct {
receiver *DatabaseReceiver
table string
columns []string
values []string
prevValues map[string]string // ロールバック用の古い値を保存
}
func (c *InsertCommand) Execute() error {
// 挿入ロジックを実行し、古い値を記録
c.prevValues = getPreviousValues(c.receiver, c.table, c.columns)
return c.receiver.ExecuteSQL(fmt.Sprintf("INSERT INTO %s VALUES (%s)", c.table, c.values))
}
func (c *InsertCommand) Undo() error {
// prevValuesを使用して挿入操作をロールバック
return c.receiver.Rollback()
}
9. コンポジットパターン
パターン定義
オブジェクトをツリー構造に組み合わせ、個々のオブジェクト(葉)と複合オブジェクト(コンテナ)を統一的に処理する。これは構造系パターンに属し、階層管理のシナリオに適している。
核心機能
- ツリー構造:部分 - 全体の階層関係をサポートする。
- 統一されたインターフェイス:クライアントは葉とコンテナを同じように扱う。
- 再帰的な処理:コンテナオブジェクトは他のコンテナまたは葉を含むことができる。
利点と欠点
利点 | 欠点 |
---|---|
階層構造の操作を簡素化する | 設計の複雑さが高くなる |
複雑な階層のトラバーサルをサポートする | 葉とコンテナのインターフェイスを厳密に統一する必要がある |
開放・閉鎖原則に準拠する | 機能拡張が全体構造に影響を与える可能性がある |
シナリオ応用
- ファイルシステム(AWS S3のバケット/オブジェクト構造):ファイルとフォルダを統一的に処理する。
- 組織構造(企業の人事システムにおける部署/従業員管理):部署はサブ部署と従業員を含むことができる。
- ECサイトの商品カタログ(Amazonのカテゴリ/サブカテゴリ/商品階層):階層的な商品管理。
- GUIコンポーネント(React Nativeにおけるビュー/テキストコンポーネントのネスト):UIコンポーネントツリーを統一的に処理する。
Go言語による実装(ファイルシステムのシミュレーション)
package composite
import "fmt"
// FileSystemNode ファイルシステムノードインターフェイス
type FileSystemNode interface {
List() string
Add(node FileSystemNode)
Remove(node FileSystemNode)
}
// File 葉ノード:ファイル
type File struct {
name string
size int
}
func (f *File) List() string {
return fmt.Sprintf("File: %s (%dKB)", f.name, f.size)
}
func (f *File) Add(node FileSystemNode) {}
func (f *File) Remove(node FileSystemNode) {}
// Directory コンテナノード:ディレクトリ
type Directory struct {
name string
children []FileSystemNode
}
func (d *Directory) List() string {
list := fmt.Sprintf("Directory: %s\n", d.name)
for _, child := range d.children {
list += fmt.Sprintf(" ├─ %s\n", child.List())
}
return list
}
func (d *Directory) Add(node FileSystemNode) {
d.children = append(d.children, node)
}
func (d *Directory) Remove(node FileSystemNode) {
for i, child := range d.children {
if child == node {
d.children = append(d.children[:i], d.children[i+1:]...)
return
}
}
}
10. イテレータパターン
パターン定義
コレクションの要素をトラバースするための統一されたインターフェイスを提供し、コレクションの内部データ構造を隠す。これは振る舞い系パターンに属し、データトラバースのシナリオに適している。
核心機能
- 抽象的なトラバース:クライアントはコレクションの内部実装を知る必要がない。
- 複数のトラバースモード:順方向、逆方向、フィルタリングなどのトラバース戦略をサポートする。
- コレクションの切り離し:コレクションとイテレータは独立して進化することができる。
利点と欠点
利点 | 欠点 |
---|---|
コレクションのアクセスインターフェイスを統一する | イテレータクラスの設計コストが増える |
複雑なデータ構造のトラバースをサポートする | カスタムイテレータはクラスの肥大化を引き起こす可能性がある |
単一責任原則に準拠する | イテレータはトラバース状態を維持する必要がある |
シナリオ応用
- ビッグデータ処理(Hadoop MapReduceにおけるデータセットのトラバース):異なるストレージ形式を統一的に処理する。
- データベースORM(GORMにおける結果セットのトラバース):異なるデータベースの返却形式を透過的に扱う。
- グラフィックレンダリング(Three.jsにおけるシーングラフノードのトラバース):3Dオブジェクトの階層構造を統一的に処理する。
- ログ分析(ELKにおけるログエントリのトラバース):異なるログストレージ形式のトラバースをサポートする。
Go言語による実装(カスタムコレクションイテレータ)
package iterator
import "fmt"
// Collection コレクションインターフェイス
type Collection interface {
CreateIterator() Iterator
AddItem(item string)
}
// StringCollection 文字列コレクションの実装
type StringCollection struct {
items []string
}
func (c *StringCollection) CreateIterator() Iterator {
return &StringIterator{collection: c, index: -1}
}
func (c *StringCollection) AddItem(item string) {
c.items = append(c.items, item)
}
// Iterator イテレータインターフェイス
type Iterator interface {
Next() bool
Current() string
}
// StringIterator 文字列イテレータの実装
type StringIterator struct {
collection *StringCollection
index int
}
func (i *StringIterator) Next() bool {
i.index++
return i.index < len(i.collection.items)
}
func (i *StringIterator) Current() string {
if i.index < len(i.collection.items) {
return i.collection.items[i.index]
}
return ""
}
// 使用例
func TraverseCollection(collection Collection) {
iterator := collection.CreateIterator()
for iterator.Next() {
fmt.Println(iterator.Current())
}
}
まとめ
Go言語は、そのインターフェイスと合成機能を通じて、デザインパターンの実装に柔軟なサポートを提供します。
- 生成系パターン:シングルトンパターンを使用してグローバル状態を制御し、ファクトリパターンを使用してオブジェクトの作成をカプセル化します。
- 構造系パターン:合成を通じてデコレータ、プロキシ、アダプターの機能拡張を実現します。
- 振る舞い系パターン:インターフェイスを活用してオブザーバー、ストラテジー、コマンドの相互作用ロジックを切り離して実装します。
実際の開発では、具体的なシナリオに応じて適切なパターンを選択する必要があります。
- マイクロサービスアーキテクチャには、ファクトリパターンとアダプターパターンが適しています。
- イベント駆動型システムには、オブザーバーパターンとコマンドパターンがおすすめです。
- 階層的なデータ管理には、コンポジットパターンとイテレータパターンが最適です。
デザインパターンを適切に使用することで、コードの保守性、拡張性、再利用性を向上させることができます。ただし、過度な設計を避け、常に実際の問題を解決することに焦点を当てる必要があります。
Leapcell: 最高のサーバーレスWebホスティング
最後に、Goサービスのデプロイに最適なプラットフォーム Leapcell をおすすめします。
🚀 好きな言語で構築
JavaScript、Python、Go、またはRustで簡単に開発できます。
🌍 無制限のプロジェクトを無料でデプロイ
使用した分だけ料金がかかります — リクエストがなければ料金は発生しません。
⚡ 従量制課金、隠れたコストは一切ありません
アイドル料金はかからず、シームレスなスケーラビリティを備えています。
🔹 Twitterでフォローしましょう: @LeapcellHQ