このプロジェクトは、Go で開発された同時駐車シミュレーターで構成され、ユーザー インターフェイスに Fyne グラフィカル ライブラリを使用します。その目的は、駐車場の挙動をリアルタイムでモデル化し、車両の入退場を同時に管理し、駐車スペースの更新状況を視覚的に表示することです。
このプロジェクトは、同時実行性の概念、Observer デザイン パターン、およびグラフィカル インターフェイスでの動的レンダリングを組み合わせています。このレポートでは、他の開発者に技術的なリファレンスを提供することを目的として、これらのツールの使用法、遭遇した課題 (特に Observer と Fyne パターン)、およびそれらがどのように解決されたかについて詳しく説明します。
Fyne は、Go でグラフィカル インターフェイスを開発するための最新のライブラリです。基本的な初期化は次の手順に従います:
シミュレーターでは、駐車場ビューを統合し、並行ロジック モデルに接続するメイン ウィンドウが作成されました。
func main() { myApp := app.New() mainWindow := myApp.NewWindow("Simulador de Parking") estacionamiento := models.NewEstacionamiento(20) parkingView := views.NewParkingView() mainScene := scenes.NewMainScene(estacionamiento, parkingView) mainWindow.SetContent(parkingView.Container) mainWindow.ShowAndRun() }
この基本的なフローにより、ビジネス ロジックとグラフィカル インターフェイスの分離が容易になります。
Observer パターンを使用する理由
Observer パターンは、モデルとビュー レイヤーの同期を保つために使用されました。車両が駐車場に出入りすると、モデルはビューに通知し、対応するグラフィック要素を更新します。このパターンは、複数のコンポーネントが同じイベントに反応する必要があるシステムに最適です。
Go で Observer パターンを使用するときに発生した問題
Go で Observer パターンを実装するのは、特に Java や C# などのオブジェクト指向言語での実装に慣れている人にとっては難しい場合があります。 Go でこのパターンを使用する一般的な問題は、オブザーバーに通知するときの同時実行性とデッドロックの処理です。
当初、イベントを報告するためにモデル (パーキング) に登録されたオブザーバーを反復処理すると、競合状態 とクラッシュが発生しました。これは、新しいオブザーバーを登録するメソッドが適切に保護されておらず、オブザーバー リストへの同時アクセスが発生したために発生していました。
解決方法
この問題を解決するために、ミューテックス (sync.Mutex) を使用してオブザーバー リストへの同時アクセスを保護しました。さらに、オブザーバーの登録とイベントの報告のための安全な方法が実装されました。
func main() { myApp := app.New() mainWindow := myApp.NewWindow("Simulador de Parking") estacionamiento := models.NewEstacionamiento(20) parkingView := views.NewParkingView() mainScene := scenes.NewMainScene(estacionamiento, parkingView) mainWindow.SetContent(parkingView.Container) mainWindow.ShowAndRun() }
プロジェクトへの実装を完了する
駐車場モデルは観察可能なサブジェクトとして機能し、MainScene およびグラフ ビューなどの他のコンポーネントは観察者として機能します。
1.オブザーバーインターフェイス定義:
func (e *Estacionamiento) RegistrarObservador(o Observer) { e.mu.Lock() defer e.mu.Unlock() e.observadores = append(e.observadores, o) } func (e *Estacionamiento) NotificarVehiculoEntra(id, cajon, espaciosDisponibles, capacidad int) { e.mu.Lock() defer e.mu.Unlock() for _, o := range e.observadores { o.OnVehiculoEntra(id, cajon, espaciosDisponibles, capacidad) } } func (e *Estacionamiento) NotificarVehiculoSale(id, cajon, espaciosDisponibles, capacidad int) { e.mu.Lock() defer e.mu.Unlock() for _, o := range e.observadores { o.OnVehiculoSale(id, cajon, espaciosDisponibles, capacidad) } }
package models type Observer interface { OnVehiculoEntra(id, cajon, espaciosDisponibles, capacidad int) OnVehiculoSale(id, cajon, espaciosDisponibles, capacidad int) }
func (e *Estacionamiento) VehiculoEntra(id int) { // Lógica para manejar la entrada del vehículo espaciosDisponibles := e.capacidad - e.ocupados e.NotificarVehiculoEntra(id, cajon, espaciosDisponibles, e.capacidad) } func (e *Estacionamiento) VehiculoSale(id int) { // Lógica para manejar la salida del vehículo espaciosDisponibles := e.capacidad - e.ocupados e.NotificarVehiculoSale(id, cajon, espaciosDisponibles, e.capacidad) }
このソリューションにより、更新の一貫性が確保され、競合状態がシステムのパフォーマンスに影響を与えないことが保証されます。
コンテキスト
主な技術的課題は、グラフィカル インターフェイス内の引き出しの位置を計算し、その色をリアルタイムで更新することでした。ドロワーは次のことを行う必要があります:
特定された問題
位置計算
絶対座標を使用して初期位置と間隔を定義しました:
func (s *MainScene) OnVehiculoEntra(id, cajon, espaciosDisponibles, capacidad int) { s.View.UpdateState(espaciosDisponibles, capacidad, id, cajon, "entra") } func (s *MainScene) OnVehiculoSale(id, cajon, espaciosDisponibles, capacidad int) { s.View.UpdateState(espaciosDisponibles, capacidad, id, cajon, "sale") }
ダイナミックレンダリング
ステータスに応じてドロワーをペイントする関数が実装されました:
xStart, yTop, yBottom := float32(185), float32(120), float32(200) spotSpacing := float32(55) // Fila superior for i := 0; i < 10; i++ { parkingSpots = append(parkingSpots, fyne.Position{X: xStart + float32(i)*spotSpacing, Y: yTop}) } // Fila inferior for i := 0; i < 10; i++ { parkingSpots = append(parkingSpots, fyne.Position{X: xStart + float32(i)*spotSpacing, Y: yBottom}) }
ビジュアル同期
視覚的な変更がシステム状態と一致していることを確認するために、メインのラベルのテキストとドロワーの状態が中央関数内で更新されました。
func main() { myApp := app.New() mainWindow := myApp.NewWindow("Simulador de Parking") estacionamiento := models.NewEstacionamiento(20) parkingView := views.NewParkingView() mainScene := scenes.NewMainScene(estacionamiento, parkingView) mainWindow.SetContent(parkingView.Container) mainWindow.ShowAndRun() }
これにより、常に正確で最新のグラフィック表現が保証されます。
結論
このプロジェクトは、同時駐車をシミュレートするという目標を達成しただけでなく、Observer パターンの使用や Fyne を使用したグラフィカル インターフェイスの作成など、実際的な開発上の問題にも直面しています。遭遇した問題と実装された解決策は、Go を始めようとする開発者、または同様の課題に直面している他の開発者のためのガイドとして機能することを目的としています。
特に、Go での Observer パターンの実装は、同時実行を安全かつ効率的に処理する方法を示しています。このレポートは、これらの問題と解決策を文書化することで、これらのツールの学習と適用に関心のあるプログラマーのコミュニティに貢献し、学習と開発のプロセスを促進することを目的としています。
この実装と解決策について質問がある場合は、私の github リポジトリ simulador-parking.git
以上が技術レポート: Go による同時駐車シミュレータの開発の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。