Go言語のインターフェースとコンポジションの基本設計例を学ぶ
生徒
「先生、Go言語でインターフェースを使ったコンポジションって何ですか?」
先生
「コンポジションとは、複数の機能を持つ小さな部品を組み合わせて、新しい機能を作る設計方法です。インターフェースと組み合わせることで柔軟な設計が可能になります。」
生徒
「部品を組み合わせるって、具体的にはどういうイメージですか?」
先生
「例えば車を作るとき、エンジンやタイヤやハンドルといった部品を組み合わせます。部品自体が別々に動作しても、車としての動きは一つにまとめられます。これがコンポジションの考え方です。」
生徒
「なるほど、コードでも同じように部品を組み合わせるんですね。」
先生
「その通りです。それではGo言語での基本的な実装例を見てみましょう。」
1. インターフェースとコンポジションの基本
Go言語では、構造体に機能を追加する際にコンポジションを使います。インターフェースは、どの構造体にも共通の操作を約束として定義するものです。コンポジションを使うと、複数の構造体を組み合わせて新しい構造体を作ることができます。
2. インターフェースを使った抽象化
共通の動作を抽象化することで、異なる構造体でも同じ操作で扱えるようになります。例えば「Speaker」というインターフェースを作ると、犬も猫も同じSpeakメソッドで鳴く動作を扱えます。
type Speaker interface {
Speak()
}
type Dog struct{}
type Cat struct{}
func (d Dog) Speak() {
fmt.Println("ワンワン")
}
func (c Cat) Speak() {
fmt.Println("ニャー")
}
3. コンポジションで機能を組み合わせる
次に、車の例を使ってコンポジションを実装します。エンジンとタイヤを部品として組み込み、車としてまとめます。
type Engine struct{}
func (e Engine) Start() {
fmt.Println("エンジン始動")
}
type Tire struct{}
func (t Tire) Rotate() {
fmt.Println("タイヤ回転")
}
type Car struct {
Engine
Tire
}
func main() {
myCar := Car{}
myCar.Start() // Engineのメソッド
myCar.Rotate() // Tireのメソッド
}
このように、Car構造体はEngineとTireを持つことで、それぞれの機能をまとめて利用できます。これがGo言語におけるコンポジションの基本です。
4. インターフェースとコンポジションを組み合わせる設計
インターフェースを使って共通の動作を抽象化し、コンポジションで部品を組み合わせると柔軟で拡張性の高い設計が可能です。
type Movable interface {
Move()
}
type EngineMovable struct{}
func (e EngineMovable) Move() {
fmt.Println("エンジンで移動")
}
type TireMovable struct{}
func (t TireMovable) Move() {
fmt.Println("タイヤで移動")
}
type Vehicle struct {
Movable
}
func main() {
car := Vehicle{Movable: EngineMovable{}}
car.Move()
bike := Vehicle{Movable: TireMovable{}}
bike.Move()
}
Vehicle構造体はMovableインターフェースを持つことで、移動方法を自由に差し替えられます。これにより、新しい部品や機能を追加しても既存のコードを変更せずに済みます。
5. 設計の利点
- 再利用可能な部品を作ることで開発効率が上がる
- コードの柔軟性と拡張性が向上する
- 異なる構造体でも同じ操作で扱える
- プログラム全体の設計がシンプルで理解しやすくなる
Go言語のインターフェースとコンポジションを組み合わせることで、複雑な機能も整理して、安全で拡張性のあるプログラム設計が可能です。