ホームページ >バックエンド開発 >Golang >技術レポート: Go による同時駐車シミュレータの開発

技術レポート: Go による同時駐車シミュレータの開発

Susan Sarandon
Susan Sarandonオリジナル
2024-12-24 19:40:11202ブラウズ

Reporte Técnico: Desarrollo de un Simulador de Estacionamiento Concurrente en Go

はじめに

このプロジェクトは、Go で開発された同時駐車シミュレーターで構成され、ユーザー インターフェイスに Fyne グラフィカル ライブラリを使用します。その目的は、駐車場の挙動をリアルタイムでモデル化し、車両の入退場を同時に管理し、駐車スペースの更新状況を視覚的に表示することです。
このプロジェクトは、同時実行性の概念、Observer デザイン パターン、およびグラフィカル インターフェイスでの動的レンダリングを組み合わせています。このレポートでは、他の開発者に技術的なリファレンスを提供することを目的として、これらのツールの使用法、遭遇した課題 (特に Observer と Fyne パターン)、およびそれらがどのように解決されたかについて詳しく説明します。

1. Fine の初期化

Fyne は、Go でグラフィカル インターフェイスを開発するための最新のライブラリです。基本的な初期化は次の手順に従います:

  1. app.New() を使用して新しいアプリケーションを作成します。
  2. app.NewWindow() を使用してメイン ウィンドウを構成します。
  3. Fyne コンテナーとウィジェットを使用してコンテンツをデザインします。
  4. ShowAndRun() を呼び出してアプリケーションを実行します。

シミュレーターでは、駐車場ビューを統合し、並行ロジック モデルに接続するメイン ウィンドウが作成されました。

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()
}

この基本的なフローにより、ビジネス ロジックとグラフィカル インターフェイスの分離が容易になります。

2.オブザーバーパターンの使用

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)
    }
}
  1. モデルからのイベント通知:
package models

type Observer interface {
    OnVehiculoEntra(id, cajon, espaciosDisponibles, capacidad int)
    OnVehiculoSale(id, cajon, espaciosDisponibles, capacidad int)
}

  1. オブザーバーの応答:
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)
}

このソリューションにより、更新の一貫性が確保され、競合状態がシステムのパフォーマンスに影響を与えないことが保証されます。

3. 技術的問題: レンダリングと位置計算

コンテキスト

主な技術的課題は、グラフィカル インターフェイス内の引き出しの位置を計算し、その色をリアルタイムで更新することでした。ドロワーは次のことを行う必要があります:

  1. 等間隔で2列に配置してください。
  2. 色を動的に変更します (ビジーの場合は赤、利用可能な場合は黒)。

特定された問題

  1. 動的位置計算: 駐車スペースは、均一な間隔で 2 列に配置する必要がありました。ただし、これらの位置の計算と更新は、レイアウトのないコンテナー (container.NewWithoutLayout()) 内の正確な座標に依存するため、複雑でした。
  2. 視覚的な同期: 複数の同時スレッドを処理する場合、ドロワーの色をリアルタイムで更新しようとすると視覚的な不一致が発生しました。変更が反映されなかったり、グラフィックエラーが発生したりする場合がありました。

位置計算
絶対座標を使用して初期位置と間隔を定義しました:

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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。