質問

下面是基于golang的ebiten引擎设计的植物大战僵尸游戏 的UI模块的子模块,请全面评估实现是否合理,有什么潜在 问题?有什么需要优化的?
# File: interactive_test.go

```go
package base

import (
"testing"
"plants-vs-zombies/internal/core/event"
"github.com/stretchr/testify/assert"
)

func TestInteractiveComponent(t *testing.T) {
t.Run("MouseEvents", func(t *testing.T) {
comp := NewInteractiveComponent()
comp.SetBounds(NewBounds(0, 0, 100, 100))

// 测试鼠标进入/离开
mouseEntered := false
mouseLeft := false

handler := NewEventHandler(func(e event.Event) bool {
mouseEntered = true
return true
})
comp.AddEventListener(event.EventTypeMouseEnter, event.EventPhaseTarget, handler, 0)

handler = NewEventHandler(func(e event.Event) bool {
mouseLeft = true
return true
})
comp.AddEventListener(event.EventTypeMouseLeave, event.EventPhaseTarget, handler, 0)

// 鼠标进入
evt := event.NewMouseEvent(event.EventTypeMouseMove, 50, 50)
comp.HandleEvent(evt)
assert.True(t, comp.IsHovered())
assert.True(t, mouseEntered)

// 鼠标离开
evt = event.NewMouseEvent(event.EventTypeMouseMove, 150, 150)
comp.HandleEvent(evt)
assert.False(t, comp.IsHovered())
assert.True(t, mouseLeft)
})

t.Run("MouseButtonEvents", func(t *testing.T) {
comp := NewInteractiveComponent()
comp.SetBounds(NewBounds(0, 0, 100, 100))

// 测试鼠标按下/释放
buttonDown := false
buttonUp := false
clicked := false

handler := NewEventHandler(func(e event.Event) bool {
buttonDown = true
return true
})
comp.AddEventListener(event.EventTypeMouseButtonDown, event.EventPhaseTarget, handler, 0)

handler = NewEventHandler(func(e event.Event) bool {
buttonUp = true
return true
})
comp.AddEventListener(event.EventTypeMouseButtonUp, event.EventPhaseTarget, handler, 0)

handler = NewEventHandler(func(e event.Event) bool {
clicked = true
return true
})
comp.AddEventListener(event.EventTypeClick, event.EventPhaseTarget, handler, 0)

// 先移动鼠标到组件上
evt := event.NewMouseEvent(event.EventTypeMouseMove, 50, 50)
comp.HandleEvent(evt)

// 鼠标按下
evt = event.NewMouseEvent(event.EventTypeMouseButtonDown, 50, 50)
comp.HandleEvent(evt)
assert.True(t, comp.IsPressed())
assert.True(t, buttonDown)

// 鼠标释放
evt = event.NewMouseEvent(event.EventTypeMouseButtonUp, 50, 50)
comp.HandleEvent(evt)
assert.False(t, comp.IsPressed())
assert.True(t, buttonUp)
assert.True(t, clicked)
})

t.Run("StateChanges", func(t *testing.T) {
comp := NewInteractiveComponent()
comp.SetBounds(NewBounds(0, 0, 100, 100))

// 设置悬停状态
evt := event.NewMouseEvent(event.EventTypeMouseMove, 50, 50)
comp.HandleEvent(evt)
assert.True(t, comp.IsHovered())

// 禁用组件
comp.SetEnabled(false)
assert.False(t, comp.IsHovered())
assert.False(t, comp.IsPressed())
assert.False(t, comp.IsFocused())

// 隐藏组件
comp.SetEnabled(true)
comp.SetVisible(false)
assert.False(t, comp.IsHovered())
assert.False(t, comp.IsPressed())
assert.False(t, comp.IsFocused())
})

t.Run("FocusManagement", func(t *testing.T) {
comp := NewInteractiveComponent()
comp.SetBounds(NewBounds(0, 0, 100, 100))

focusGained := false
focusLost := false

handler := NewEventHandler(func(e event.Event) bool {
focusGained = true
return true
})
comp.AddEventListener(event.EventTypeFocusGain, event.EventPhaseTarget, handler, 0)

handler = NewEventHandler(func(e event.Event) bool {
focusLost = true
return true
})
comp.AddEventListener(event.EventTypeFocusLoss, event.EventPhaseTarget, handler, 0)

// 通过鼠标点击获得焦点
evt := event.NewMouseEvent(event.EventTypeMouseButtonDown, 50, 50)
comp.HandleEvent(evt)
assert.True(t, comp.IsFocused())
assert.True(t, focusGained)

// 禁用时失去焦点
comp.SetEnabled(false)
assert.False(t, comp.IsFocused())
assert.True(t, focusLost)
})

t.Run("EventPropagation", func(t *testing.T) {
parent := NewInteractiveComponent()
child := NewInteractiveComponent()
parent.AddChild(child)
child.SetBounds(NewBounds(0, 0, 100, 100))

var eventOrder []string
parentHandled := false
childHandled := false

handler := NewEventHandler(func(e event.Event) bool {
eventOrder = append(eventOrder, "parent")
parentHandled = true
return true
})
parent.AddEventListener(event.EventTypeMouseMove, event.EventPhaseTarget, handler, 0)

handler = NewEventHandler(func(e event.Event) bool {
eventOrder = append(eventOrder, "child")
childHandled = true
return true
})
child.AddEventListener(event.EventTypeMouseMove, event.EventPhaseTarget, handler, 0)

// 触发子组件事件
evt := event.NewMouseEvent(event.EventTypeMouseMove, 50, 50)
evt.SetBubbles(true) // Set event to bubble
child.HandleEvent(evt)

assert.True(t, childHandled)
assert.True(t, parentHandled)
assert.Equal(t, []string{"child", "parent"}, eventOrder)
})
}

```

# File: bounds_test.go

```go
package base

import (
"testing"
"github.com/stretchr/testify/assert"
)

func TestBaseBounds(t *testing.T) {
t.Run("Creation", func(t *testing.T) {
bounds := NewBounds(10, 20, 100, 200)
assert.Equal(t, float64(10), bounds.X())
assert.Equal(t, float64(20), bounds.Y())
assert.Equal(t, float64(100), bounds.Width())
assert.Equal(t, float64(200), bounds.Height())
})

t.Run("Setters", func(t *testing.T) {
bounds := NewBounds(0, 0, 0, 0)
bounds.SetX(10)
bounds.SetY(20)
bounds.SetWidth(100)
bounds.SetHeight(200)

assert.Equal(t, float64(10), bounds.X())
assert.Equal(t, float64(20), bounds.Y())
assert.Equal(t, float64(100), bounds.Width())
assert.Equal(t, float64(200), bounds.Height())
})

t.Run("Contains", func(t *testing.T) {
bounds := NewBounds(10, 20, 100, 200)

// 测试边界内的点
assert.True(t, bounds.Contains(10, 20)) // 左上角
assert.True(t, bounds.Contains(110, 220)) // 右下角
assert.True(t, bounds.Contains(60, 120)) // 中心点

// 测试边界外的点
assert.False(t, bounds.Contains(9, 20)) // 左边界外
assert.False(t, bounds.Contains(111, 120)) // 右边界外
assert.False(t, bounds.Contains(60, 19)) // 上边界外
assert.False(t, bounds.Contains(60, 221)) // 下边界外
})

t.Run("Intersects", func(t *testing.T) {
bounds1 := NewBounds(10, 20, 100, 200)
bounds2 := NewBounds(50, 60, 100, 200) // 相交
bounds3 := NewBounds(200, 300, 100, 200) // 不相交

assert.True(t, bounds1.Intersects(bounds2))
assert.True(t, bounds2.Intersects(bounds1))
assert.False(t, bounds1.Intersects(bounds3))
assert.False(t, bounds3.Intersects(bounds1))
})

t.Run("Clone", func(t *testing.T) {
bounds := NewBounds(10, 20, 100, 200)
clone := bounds.Clone()

assert.Equal(t, bounds.X(), clone.X())
assert.Equal(t, bounds.Y(), clone.Y())
assert.Equal(t, bounds.Width(), clone.Width())
assert.Equal(t, bounds.Height(), clone.Height())

// 修改克隆不应影响原对象
clone.SetX(30)
assert.NotEqual(t, bounds.X(), clone.X())
})

t.Run("String", func(t *testing.T) {
bounds := NewBounds(10, 20, 100, 200)
expected := "Bounds(x:10.0, y:20.0, w:100.0, h:200.0)"
assert.Equal(t, expected, bounds.String())
})
}
```

# File: container.go

```go
package base

import (
"fmt"
"plants-vs-zombies/internal/core/event"
"sync"
)

// BaseContainer 提供了容器组件的基本实现
type BaseContainer struct {
*BaseComponent
layout SimpleLayout
padding *Margins
margin *Margins
debugger *LayoutDebugger

// 用于跟踪事件处理,防止递归
eventProcessing sync.Map
}

// NewBaseContainer 创建新的容器组件
func NewBaseContainer() *BaseContainer {
c := &BaseContainer{
BaseComponent: NewBaseComponent(),
padding: NewMargins(0, 0, 0, 0),
margin: NewMargins(0, 0, 0, 0),
}
return c
}

// GetPadding 获取内边距
func (c *BaseContainer) GetPadding() *Margins {
c.RLock()
defer c.RUnlock()
return c.padding.Clone()
}

// SetPadding 设置内边距
func (c *BaseContainer) SetPadding(padding *Margins) {
c.Lock()
defer c.Unlock()

if padding != nil {
c.padding = padding.Clone()
if c.layout != nil {
c.layout.Layout(c)
}
}
}

// GetMargin 获取外边距
func (c *BaseContainer) GetMargin() *Margins {
c.RLock()
defer c.RUnlock()
return c.margin.Clone()
}

// SetMargin 设置外边距
func (c *BaseContainer) SetMargin(margin *Margins) {
c.Lock()
defer c.Unlock()

if margin != nil {
c.margin = margin.Clone()
if c.layout != nil {
c.layout.Layout(c)
}
}
}

// Clear 清除所有子组件
func (c *BaseContainer) Clear() {
c.Lock()
defer c.Unlock()

c.BaseComponent.Clear()
if c.layout != nil {
c.layout.Layout(c)
}
}

// Layout 执行布局
func (c *BaseContainer) Layout() {
if c.layout != nil {
c.layout.Layout(c)
}
}

// AddComponent 添加组件
func (c *BaseContainer) AddComponent(component Component) {
c.Lock()
defer c.Unlock()

c.BaseComponent.AddChild(component)
if c.layout != nil {
c.layout.Layout(c)
}
}

// RemoveComponent 移除组件
func (c *BaseContainer) RemoveComponent(component Component) {
c.Lock()
defer c.Unlock()

c.BaseComponent.RemoveChild(component)
if c.layout != nil {
c.layout.Layout(c)
}
}

// GetComponents 获取所有子组件
func (c *BaseContainer) GetComponents() []Component {
c.RLock()
defer c.RUnlock()
return c.BaseComponent.Children()
}

// HandleEvent 处理事件
func (c *BaseContainer) HandleEvent(evt event.Event) bool {
// 防止重复处理
eventKey := fmt.Sprintf("%p-%s", evt, c.id)
if _, exists := c.eventProcessing.LoadOrStore(eventKey, true); exists {
return false
}
defer c.eventProcessing.Delete(eventKey)

// 如果组件被禁用或隐藏,不处理事件
if !c.IsEnabled() || !c.IsVisible() {
return false
}

// 如果没有设置事件目标,将当前组件设为目标
if evt.Target() == nil {
evt.SetTarget(c.eventTarget)
evt.SetPhase(event.EventPhaseCapturing)
}

// 根据事件阶段处理
switch evt.Phase() {
case event.EventPhaseCapturing:
// 先处理自己的捕获阶段监听器
if c.BaseComponent.HandleEvent(evt) {
return true
}

// 如果当前组件是目标,切换到目标阶段
if c.eventTarget == evt.Target() {
evt.SetPhase(event.EventPhaseTarget)
return c.HandleEvent(evt)
}

// 向下传播到子组件
var children []Component
func() {
c.RLock()
defer c.RUnlock()
children = make([]Component, len(c.children))
copy(children, c.children)
}()

for _, child := range children {
// 检查子组件是否是目标
var isTarget bool
if bc, ok := child.(*BaseComponent); ok {
isTarget = bc.eventTarget == evt.Target()
}

// 检查子组件是否是容器并且包含目标
var containsTarget bool
if container, ok := child.(*BaseContainer); ok {
containsTarget = container.Contains(0, 0)
}

// 如果子��件是目标或者包含目标,则传播事件
if isTarget || containsTarget {
if child.HandleEvent(evt) {
return true
}
}
}

case event.EventPhaseTarget:
// 处理目标阶段
handled := c.BaseComponent.HandleEvent(evt)

// 如果事件可以冒泡,切换到冒泡阶段并开始冒泡
if evt.Bubbles() {
evt.SetPhase(event.EventPhaseBubbling)
if c.parent != nil {
parentHandled := c.parent.HandleEvent(evt)
return handled || parentHandled
}
}
return handled

case event.EventPhaseBubbling:
// 处理冒泡阶段
if !evt.Bubbles() {
return false
}

// 处理自己的冒泡阶段监听器
handled := c.BaseComponent.HandleEvent(evt)
if handled {
return true
}

// 继续向上冒泡
if c.parent != nil {
return c.parent.HandleEvent(evt)
}
}

return false
}

// findEventPath 查找从当前组件到目标组件的路径
func (c *BaseContainer) findEventPath(target event.EventTarget) []Component {
// 如果当前组件是目标
if c.eventTarget == target {
return []Component{c}
}

// 遍历子组件查找路径
for _, child := range c.GetComponents() {
// 如果子组件是目标
if child.(*BaseComponent).eventTarget == target {
return []Component{child}
}

// 如果子组件是容器,递归查找
if container, ok := child.(*BaseContainer); ok {
if path := container.findEventPath(target); len(path) > 0 {
return append([]Component{child}, path...)
}
}
}

return nil
}

// EmitEvent 发送事件
func (c *BaseContainer) EmitEvent(eventType event.EventType) {
evt := event.NewBaseEvent(eventType, true)
evt.SetTarget(c.eventTarget)

// 查找根组件
var root Component = c
var parent Component

// 使用函数闭包限制锁的范围
func() {
c.RLock()
defer c.RUnlock()
parent = c.parent
}()

// 在锁外查找根组件
for parent != nil {
root = parent
parent = parent.Parent()
}

// 设置初始阶段并开始传播
evt.SetPhase(event.EventPhaseCapturing)
root.HandleEvent(evt)
}

// findRoot 查找根组件
func (c *BaseContainer) findRoot() Component {
current := Component(c)
for p := c.parent; p != nil; p = p.Parent() {
current = p
}
return current
}

// Contains 检查点是否在容器内
func (c *BaseContainer) Contains(x, y float64) bool {
// 先检查自己的边界
if !c.bounds.Contains(x, y) {
return false
}

// 再检查子组件
for _, child := range c.GetComponents() {
if child.GetBounds().Contains(x, y) {
return true
}
}

return true
}

// SetLayout 设置容器的布局管理器
func (c *BaseContainer) SetLayout(layout SimpleLayout) {
c.Lock()
defer c.Unlock()
c.layout = layout
}

// GetLayout 获取容器的布局管理器
func (c *BaseContainer) GetLayout() SimpleLayout {
c.RLock()
defer c.RUnlock()
return c.layout
}

// SetDebugger 设置布局调试器
func (c *BaseContainer) SetDebugger(debugger *LayoutDebugger) {
c.Lock()
defer c.Unlock()
c.debugger = debugger
}

// GetDebugger 获取布局调试器
func (c *BaseContainer) GetDebugger() *LayoutDebugger {
c.RLock()
defer c.RUnlock()
return c.debugger
}

```

# File: component_test.go

```go
package base

import (
"sync"
"testing"
"plants-vs-zombies/internal/core/event"
"github.com/stretchr/testify/assert"
)

func TestBaseComponent(t *testing.T) {
t.Run("Initialization", func(t *testing.T) {
comp := NewBaseComponent()
assert.NotNil(t, comp)
assert.True(t, comp.IsEnabled())
assert.True(t, comp.IsVisible())
assert.False(t, comp.IsFocused())
assert.NotNil(t, comp.GetBounds())
assert.Empty(t, comp.Children())
})

t.Run("StateManagement", func(t *testing.T) {
comp := NewBaseComponent()

// 测试启用/禁用
comp.SetEnabled(false)
assert.False(t, comp.IsEnabled())
comp.SetEnabled(true)
assert.True(t, comp.IsEnabled())

// 测试显示/隐藏
comp.SetVisible(false)
assert.False(t, comp.IsVisible())
comp.SetVisible(true)
assert.True(t, comp.IsVisible())

// 测试焦点
comp.SetFocused(true)
assert.True(t, comp.IsFocused())
comp.SetFocused(false)
assert.False(t, comp.IsFocused())
})

t.Run("ComponentTree", func(t *testing.T) {
parent := NewBaseComponent()
child1 := NewBaseComponent()
child2 := NewBaseComponent()

// 测试添加子组件
parent.AddChild(child1)
parent.AddChild(child2)
assert.Equal(t, 2, len(parent.Children()))
assert.Equal(t, parent, child1.Parent())
assert.Equal(t, parent, child2.Parent())

// 测试移除子组件
parent.RemoveChild(child1)
assert.Equal(t, 1, len(parent.Children()))
assert.Nil(t, child1.Parent())
assert.Equal(t, parent, child2.Parent())
})

t.Run("EventHandling", func(t *testing.T) {
comp := NewBaseComponent()
handled := false

// 添加事件监听器
handler := NewEventHandler(func(e event.Event) bool {
handled = true
return true
})
comp.AddEventListener(event.EventTypeMouseMove, event.EventPhaseTarget, handler, 0)

// 触发事件
evt := event.NewBaseEvent(event.EventTypeMouseMove, true)
evt.SetTarget(comp.eventTarget)
comp.DispatchEvent(evt)

assert.True(t, handled)
})

t.Run("Layout", func(t *testing.T) {
container := NewBaseComponent()
container.SetBounds(NewBounds(0, 0, 200, 200))

child := NewBaseComponent()
child.SetBounds(NewBounds(0, 0, 50, 50))
container.AddChild(child)

// 测试流式布局
layout := NewSimpleFlowLayout(10, Horizontal)
container.SetLayout(layout)
container.Layout()

assert.Equal(t, float64(0), child.GetBounds().X())
assert.Equal(t, float64(0), child.GetBounds().Y())
})
}

func TestComponentConcurrency(t *testing.T) {
t.Run("ConcurrentChildOperations", func(t *testing.T) {
// 测试并发添加/删除子组件的操作
parent := NewBaseComponent()
var wg sync.WaitGroup

// 并发添加和删除子组件
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
child := NewBaseComponent()
parent.AddChild(child)
parent.RemoveChild(child)
}()
}

wg.Wait()
assert.Empty(t, parent.Children())
})

t.Run("ConcurrentStateModification", func(t *testing.T) {
comp := NewBaseComponent()
var wg sync.WaitGroup
iterations := 1000

for i := 0; i < iterations; i++ {
wg.Add(1)
go func() {
defer wg.Done()
comp.SetEnabled(true)
comp.SetVisible(true)
comp.SetFocused(true)
_ = comp.IsEnabled()
_ = comp.IsVisible()
_ = comp.IsFocused()
}()
}
wg.Wait()
})

t.Run("ConcurrentEventHandling", func(t *testing.T) {
comp := NewBaseComponent()
var wg sync.WaitGroup
eventCount := 100

// 添加事件处理器
handler := NewEventHandler(func(e event.Event) bool {
return true
})
comp.AddEventListener(event.EventTypeMouseMove, event.EventPhaseTarget, handler, 0)

// 并发触发事件
for i := 0; i < eventCount; i++ {
wg.Add(1)
go func() {
defer wg.Done()
evt := event.NewBaseEvent(event.EventTypeMouseMove, true)
evt.SetTarget(comp.eventTarget)
comp.DispatchEvent(evt)
}()
}
wg.Wait()
})
}

func TestComponentLifecycle(t *testing.T) {
t.Run("InitAndDestroy", func(t *testing.T) {
parent := NewBaseComponent()
child := NewBaseComponent()
parent.AddChild(child)

// 测试初始化
parent.Init()
assert.True(t, parent.initialized)
assert.True(t, child.initialized)

// 测试销毁
parent.Destroy()
assert.Empty(t, parent.Children())
assert.Nil(t, child.Parent())
assert.Nil(t, parent.eventTarget)
})

t.Run("ComponentPool", func(t *testing.T) {
// 从池中获取组件
comp := GetComponent()
assert.NotNil(t, comp)
assert.True(t, comp.IsEnabled())
assert.True(t, comp.IsVisible())

// 修改组件状态
comp.SetEnabled(false)
comp.SetVisible(false)
child := NewBaseComponent()
comp.AddChild(child)

// 放回池中
PutComponent(comp)

// 再次获取,验证状态已重置
comp2 := GetComponent()
assert.True(t, comp2.IsEnabled())
assert.True(t, comp2.IsVisible())
assert.Empty(t, comp2.Children())
})
}

func BenchmarkComponent(b *testing.B) {
b.Run("ChildOperations", func(b *testing.B) {
parent := NewBaseComponent()
child := NewBaseComponent()

b.ResetTimer()
for i := 0; i < b.N; i++ {
parent.AddChild(child)
parent.RemoveChild(child)
}
})

b.Run("EventDispatch", func(b *testing.B) {
comp := NewBaseComponent()
evt := event.NewBaseEvent(event.EventTypeMouseMove, true)
evt.SetTarget(comp.eventTarget)

handler := NewEventHandler(func(e event.Event) bool {
return true
})
comp.AddEventListener(event.EventTypeMouseMove, event.EventPhaseTarget, handler, 0)

b.ResetTimer()
for i := 0; i < b.N; i++ {
comp.DispatchEvent(evt)
}
})

b.Run("ComponentPool", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
comp := GetComponent()
PutComponent(comp)
}
})
}

```

# File: lifecycle.go

```go
package base

// LifecycleState represents the current state of a component's lifecycle
type LifecycleState int

const (
// LifecycleStateUnmounted indicates the component is not mounted
LifecycleStateUnmounted LifecycleState = iota
// LifecycleStateMounting indicates the component is in the process of mounting
LifecycleStateMounting
// LifecycleStateMounted indicates the component is mounted and active
LifecycleStateMounted
// LifecycleStateUnmounting indicates the component is in the process of unmounting
LifecycleStateUnmounting
)

// LifecycleAware defines the interface for components that need lifecycle management
type LifecycleAware interface {
// GetLifecycleState returns the current lifecycle state
GetLifecycleState() LifecycleState
// SetLifecycleState sets the lifecycle state
SetLifecycleState(state LifecycleState)

// Lifecycle hooks
BeforeMount()
AfterMount()
BeforeUnmount()
AfterUnmount()

// Update is called when the component needs to update
Update()
}

// LifecycleManager provides lifecycle management functionality
type LifecycleManager struct {
state LifecycleState
}

// NewLifecycleManager creates a new lifecycle manager
func NewLifecycleManager() *LifecycleManager {
return &LifecycleManager{
state: LifecycleStateUnmounted,
}
}

// GetLifecycleState returns the current lifecycle state
func (l *LifecycleManager) GetLifecycleState() LifecycleState {
return l.state
}

// SetLifecycleState sets the lifecycle state
func (l *LifecycleManager) SetLifecycleState(state LifecycleState) {
l.state = state
}

// Mount performs the mounting process
func (l *LifecycleManager) Mount(component LifecycleAware) {
if l.state != LifecycleStateUnmounted {
return
}

l.state = LifecycleStateMounting
component.BeforeMount()
l.state = LifecycleStateMounted
component.AfterMount()
}

// Unmount performs the unmounting process
func (l *LifecycleManager) Unmount(component LifecycleAware) {
if l.state != LifecycleStateMounted {
return
}

l.state = LifecycleStateUnmounting
component.BeforeUnmount()
l.state = LifecycleStateUnmounted
component.AfterUnmount()
}

// BaseLifecycleComponent provides a base implementation of LifecycleAware
type BaseLifecycleComponent struct {
*LifecycleManager
}

// NewBaseLifecycleComponent creates a new base lifecycle component
func NewBaseLifecycleComponent() *BaseLifecycleComponent {
return &BaseLifecycleComponent{
LifecycleManager: NewLifecycleManager(),
}
}

// BeforeMount is called before the component is mounted
func (b *BaseLifecycleComponent) BeforeMount() {
// Default implementation does nothing
}

// AfterMount is called after the component is mounted
func (b *BaseLifecycleComponent) AfterMount() {
// Default implementation does nothing
}

// BeforeUnmount is called before the component is unmounted
func (b *BaseLifecycleComponent) BeforeUnmount() {
// Default implementation does nothing
}

// AfterUnmount is called after the component is unmounted
func (b *BaseLifecycleComponent) AfterUnmount() {
// Default implementation does nothing
}

// Update is called when the component needs to update
func (b *BaseLifecycleComponent) Update() {
// Default implementation does nothing
}

```

# File: component.go

```go
// Package base provides core UI components and interfaces
package base

import (
"plants-vs-zombies/internal/core/event"
"sync"

"github.com/hajimehoshi/ebiten/v2"
)

// Handler 用于定义事件处理器接口
type Handler interface {
Handle(event.Event) bool
GetID() string
}

// BaseComponent 提供了基本的组件功能
type BaseComponent struct {
sync.RWMutex
id string
enabled bool
visible bool
focused bool
bounds *BaseBounds
parent Component
children []Component
eventTarget *event.BaseEventTarget
constraints *BaseLayoutConstraints
layout SimpleLayout
flexible bool
flexWeight float64
initialized bool
captureListeners map[event.EventType][]event.Handler
bubbleListeners map[event.EventType][]event.Handler
targetListeners map[event.EventType][]event.Handler
listenersMutex sync.RWMutex
eventListeners map[EventListenerKey][]event.Handler
}

// EventListenerKey 用于标识事件监听器
type EventListenerKey struct {
Type event.EventType
Phase event.EventPhase
UseCapture bool
}

// NewBaseComponent 创建新的基础组件
func NewBaseComponent() *BaseComponent {
b := &BaseComponent{
enabled: true,
visible: true,
bounds: NewBounds(0, 0, 0, 0),
children: make([]Component, 0),
eventTarget: event.NewBaseEventTarget(),
constraints: NewBaseLayoutConstraints(),
flexible: false,
flexWeight: 1.0,
}
return b
}

// Init 初始化组件
func (b *BaseComponent) Init() {
if b.initialized {
return
}

// 初始化事件目标
if b.eventTarget == nil {
b.eventTarget = event.NewBaseEventTarget()
}

// 初始���子组件
for _, child := range b.children {
child.Init()
}

b.initialized = true

// 发送初始化完成事件
b.EmitEvent(event.EventTypeInit)
}

// Update 更新组件状态
func (b *BaseComponent) Update() error {
if !b.enabled || !b.visible {
return nil
}

// 更新子组件
for _, child := range b.children {
if err := child.Update(); err != nil {
return err
}
}

return nil
}

// Draw 绘制组件
func (b *BaseComponent) Draw(screen *ebiten.Image) {
if !b.visible {
return
}

// 绘制子组件
for _, child := range b.children {
child.Draw(screen)
}
}

// Destroy 清理组件资源
func (b *BaseComponent) Destroy() {
// 发送销毁事件
b.EmitEvent(event.EventTypeDestroy)

// 清理子组件
for _, child := range b.children {
child.Destroy()
}

// 从父组件移除
if b.parent != nil {
b.parent.RemoveChild(b)
}

// 清理引用
b.children = nil
b.parent = nil
b.eventTarget = nil
b.layout = nil
b.initialized = false
}

// 实现 Component 接口
func (b *BaseComponent) IsEnabled() bool {
b.RLock()
defer b.RUnlock()
return b.enabled
}

func (b *BaseComponent) SetEnabled(enabled bool) {
// 先获取当前状态
var stateChanged bool
func() {
b.Lock()
defer b.Unlock()
stateChanged = b.enabled != enabled
b.enabled = enabled
}()

// 如果状态改变,在锁外发送事件
if stateChanged {
// 创建事件
var evt event.Event
if enabled {
evt = event.NewBaseEvent(event.EventTypeEnabled, true)
} else {
evt = event.NewBaseEvent(event.EventTypeDisabled, true)
}
evt.SetTarget(b.eventTarget)

// 直接调用 HandleEvent,避免通过 EmitEvent
if b.parent != nil {
b.parent.HandleEvent(evt)
} else {
b.HandleEvent(evt)
}
}
}

func (b *BaseComponent) IsVisible() bool {
b.RLock()
defer b.RUnlock()
return b.visible
}

func (b *BaseComponent) SetVisible(visible bool) {
// 先获取当前状态
var stateChanged bool
func() {
b.Lock()
defer b.Unlock()
stateChanged = b.visible != visible
b.visible = visible
}()

// 如果状态改变,在锁外发送事件
if stateChanged {
// 创建事件
var evt event.Event
if visible {
evt = event.NewBaseEvent(event.EventTypeShow, true)
} else {
evt = event.NewBaseEvent(event.EventTypeHide, true)
}
evt.SetTarget(b.eventTarget)

// 直接调用 HandleEvent,避免通过 EmitEvent
if b.parent != nil {
b.parent.HandleEvent(evt)
} else {
b.HandleEvent(evt)
}
}
}

func (b *BaseComponent) GetBounds() *BaseBounds {
return b.bounds
}

func (b *BaseComponent) SetBounds(bounds *BaseBounds) {
if b.bounds.X() != bounds.X() || b.bounds.Y() != bounds.Y() {
b.EmitEvent(event.EventTypeMove)
}
if b.bounds.Width() != bounds.Width() || b.bounds.Height() != bounds.Height() {
b.EmitEvent(event.EventTypeResize)
}
b.bounds = bounds
}

func (b *BaseComponent) Parent() Component {
return b.parent
}

func (b *BaseComponent) Children() []Component {
b.RLock()
defer b.RUnlock()

result := make([]Component, len(b.children))
copy(result, b.children)
return result
}

func (b *BaseComponent) AddChild(child Component) {
b.Lock()
defer b.Unlock()

if child == nil {
return
}

// 如果子组件已经有父组件,先从原父组件中移除
if child.Parent() != nil {
child.Parent().RemoveChild(child)
}

b.children = append(b.children, child)
child.SetParent(b)
}

// setParentNoEvent 设置父组件但不触发事件
func (b *BaseComponent) setParentNoEvent(parent Component) {
b.Lock()
b.parent = parent
b.Unlock()
}

func (b *BaseComponent) RemoveChild(child Component) {
b.Lock()
defer b.Unlock()

if child == nil {
return
}

for i, c := range b.children {
if c == child {
b.children = append(b.children[:i], b.children[i+1:]...)
child.SetParent(nil)
break
}
}
}

// 实现 event.EventTarget 接口
func (b *BaseComponent) HandleEvent(evt event.Event) bool {
if evt.IsPropagationStopped() {
return false
}

// 设置当前目标
evt.SetCurrentTarget(b.GetEventTarget())

// 根据事件相应的处理方法
switch evt.Phase() {
case event.EventPhaseCapturing:
// 捕获阶段:从根到目标的传播
b.handleCapturingPhase(evt)
case event.EventPhaseTarget:
// 目标阶段:在目标上触发事件
b.handleTargetPhase(evt)
case event.EventPhaseBubbling:
// 冒泡阶段:从目标回到根的传播
b.handleBubblingPhase(evt)
}

return !evt.IsPropagationStopped()
}

// handleCapturingPhase 处理捕获阶段
func (b *BaseComponent) handleCapturingPhase(evt event.Event) {
// 先调用当前组件的捕获阶段监听器
key := EventListenerKey{
Type: evt.Type(),
Phase: event.EventPhaseCapturing,
UseCapture: true,
}

b.callEventListeners(key, evt)

// 如果事件传播被停止,直接返回
if evt.IsPropagationStopped() {
return
}

// 如果当前组件不是目标,继续向下传播
if evt.Target() != b.GetEventTarget() {
// 获取子组件并继续传播
for _, child := range b.EventChildren() {
evt.SetPhase(event.EventPhaseCapturing)
child.HandleEvent(evt)
if evt.IsPropagationStopped() {
return
}
}
} else {
// 如果是目标,切换到目标阶段
evt.SetPhase(event.EventPhaseTarget)
b.handleTargetPhase(evt)
}
}

// handleTargetPhase 处理目标阶段
func (b *BaseComponent) handleTargetPhase(evt event.Event) {
// 在目标上调用所有监听器
key := EventListenerKey{
Type: evt.Type(),
Phase: event.EventPhaseTarget,
}
b.callEventListeners(key, evt)

// 如果事件可以冒泡且未被停止,切换到冒泡阶段
if evt.Bubbles() && !evt.IsPropagationStopped() {
evt.SetPhase(event.EventPhaseBubbling)
if parent := b.EventParent(); parent != nil {
parent.HandleEvent(evt)
}
}
}

// handleBubblingPhase 处理冒泡阶段
func (b *BaseComponent) handleBubblingPhase(evt event.Event) {
// 调用冒泡阶段的监听器
key := EventListenerKey{
Type: evt.Type(),
Phase: event.EventPhaseBubbling,
UseCapture: false,
}
b.callEventListeners(key, evt)

// 如果事件未被停止且有父组件,继续冒泡
if !evt.IsPropagationStopped() {
if parent := b.EventParent(); parent != nil {
evt.SetPhase(event.EventPhaseBubbling)
parent.HandleEvent(evt)
}
}
}

// callEventListeners 用指定类型和阶段的所有事件监听器
func (b *BaseComponent) callEventListeners(key EventListenerKey, evt event.Event) {
if handlers, ok := b.eventListeners[key]; ok {
for _, handler := range handlers {
if handler.HandleEvent(evt) {
evt.StopPropagation()
break
}
}
}
}

func (b *BaseComponent) DispatchEvent(evt event.Event) bool {
if evt == nil {
return false
}

// 如果没有设置件目标,将当前组件设为目标
if evt.Target() == nil {
evt.SetTarget(b.eventTarget)
}

// 如果没有设置事件阶段,从捕获阶段开始
if evt.Phase() == event.EventPhaseNone {
evt.SetPhase(event.EventPhaseCapturing)
}

return b.HandleEvent(evt)
}

// AddEventListener 添加事件监听器
func (b *BaseComponent) AddEventListener(eventType event.EventType, phase event.EventPhase, handler event.Handler, priority int) {
if b.eventListeners == nil {
b.eventListeners = make(map[EventListenerKey][]event.Handler)
}

key := EventListenerKey{
Type: eventType,
Phase: phase,
UseCapture: phase == event.EventPhaseCapturing,
}

b.eventListeners[key] = append(b.eventListeners[key], handler)
}

func (b *BaseComponent) RemoveEventListener(eventType event.EventType, phase event.EventPhase, handler event.Handler) {
if handler == nil {
return
}

key := EventListenerKey{
Type: eventType,
Phase: phase,
UseCapture: phase == event.EventPhaseCapturing,
}

if handlers, ok := b.eventListeners[key]; ok {
for i, h := range handlers {
if h.GetID() == handler.GetID() {
b.eventListeners[key] = append(handlers[:i], handlers[i+1:]...)
break
}
}
}
}

// 实现 Interactive 接口
func (b *BaseComponent) IsFocused() bool {
b.RLock()
defer b.RUnlock()
return b.focused
}

func (b *BaseComponent) SetFocused(focused bool) {
// 先获取当前状态
var stateChanged bool
func() {
b.Lock()
defer b.Unlock()
stateChanged = b.focused != focused
b.focused = focused
}()

// 如果状态改变,在锁外发送事件
if stateChanged {
// 创建事件
var evt event.Event
if focused {
evt = event.NewBaseEvent(event.EventTypeFocusGain, true)
} else {
evt = event.NewBaseEvent(event.EventTypeFocusLoss, true)
}
evt.SetTarget(b.eventTarget)

// 直接调用 HandleEvent,避免通过 DispatchEvent
if b.parent != nil {
b.parent.HandleEvent(evt)
} else {
// 如果没有父组件,直接处理事件
func() {
b.listenersMutex.RLock()
defer b.listenersMutex.RUnlock()

var handlers []event.Handler
if focused {
handlers = b.targetListeners[event.EventTypeFocusGain]
} else {
handlers = b.targetListeners[event.EventTypeFocusLoss]
}

if len(handlers) > 0 {
// 复制处理器列表,避免在持有锁时调用处理器
handlersCopy := make([]event.Handler, len(handlers))
copy(handlersCopy, handlers)

// 在锁外调用处理器
for _, handler := range handlersCopy {
if handler != nil {
handler.HandleEvent(evt)
}
}
}
}()
}
}
}

// 实现 Container 接口
func (b *BaseComponent) Layout() {
if b.layout != nil && len(b.children) > 0 {
// 如果有布局管理器且有子组件,则进行布局
b.layout.Layout(b)
}
}

func (b *BaseComponent) SetLayout(layout SimpleLayout) {
b.layout = layout
}

func (b *BaseComponent) AddComponent(component Component) {
b.AddChild(component)
}

func (b *BaseComponent) RemoveComponent(component Component) {
b.RemoveChild(component)
}

func (b *BaseComponent) GetComponents() []Component {
return b.Children()
}

func (b *BaseComponent) Clear() {
b.Lock()
defer b.Unlock()
for _, child := range b.children {
if child != nil {
child.Destroy()
}
}
b.children = make([]Component, 0)
b.EmitEvent(event.EventTypeChildrenCleared)
}

func (b *BaseComponent) GetPadding() *Margins {
return &Margins{} // 默认返回空边距
}

func (b *BaseComponent) SetPadding(*Margins) {
// 基础组件不实现边距
}

func (b *BaseComponent) GetMargin() *Margins {
return &Margins{} // 默认返回空边距
}

func (b *BaseComponent) SetMargin(*Margins) {
// 基础组件不实现边距
}

// SetParent 设置父组件
func (b *BaseComponent) SetParent(parent Component) {
var changed bool

func() {
b.Lock()
defer b.Unlock()

if b.parent != parent {
b.parent = parent
changed = true
}
}()

// 如果父组件发生变化,在锁外发送事件
if changed {
evt := event.NewBaseEvent(event.EventTypeParentChanged, true)
evt.SetTarget(b.eventTarget)

// 直接处理事件,避免使用 DispatchEvent
var handlers []event.Handler
func() {
b.listenersMutex.RLock()
defer b.listenersMutex.RUnlock()

if h := b.targetListeners[event.EventTypeParentChanged]; len(h) > 0 {
handlers = make([]event.Handler, len(h))
copy(handlers, h)
}
}()

// 在锁外调用处理器
for _, handler := range handlers {
if handler != nil {
handler.HandleEvent(evt)
}
}
}
}

// SetConstraints 设置布局约束
func (b *BaseComponent) SetConstraints(constraints *BaseLayoutConstraints) {
b.constraints = constraints
}

// GetConstraints 获取布局约束
func (b *BaseComponent) GetConstraints() *BaseLayoutConstraints {
return b.constraints
}

// SetFlexible 设置是否可伸缩
func (b *BaseComponent) SetFlexible(flexible bool) {
b.flexible = flexible
}

// SetFlexWeight 设置伸缩权重
func (b *BaseComponent) SetFlexWeight(weight float64) {
b.flexWeight = weight
}

// EmitEvent 发送事件
func (b *BaseComponent) EmitEvent(eventType event.EventType) {
if b == nil {
return
}

// 创建事件
evt := event.NewBaseEvent(eventType, true)
evt.SetTarget(b.eventTarget)

// 获取处理器的副本,避免长时间持有锁
var handlers []event.Handler
func() {
b.listenersMutex.RLock()
defer b.listenersMutex.RUnlock()

if h := b.targetListeners[eventType]; len(h) > 0 {
handlers = make([]event.Handler, len(h))
copy(handlers, h)
}
}()

// 在锁外调用处理器
for _, handler := range handlers {
if handler != nil {
handler.HandleEvent(evt)
}
}
}

// OnEvent 添加事件处理器
func (b *BaseComponent) OnEvent(eventType event.EventType, handler func(event.Event) bool) {
b.AddEventListener(eventType, event.EventPhaseTarget, event.NewHandler(handler, event.EventPhaseTarget), 0)
}

// OffEvent 移除事件处理器
func (b *BaseComponent) OffEvent(eventType event.EventType, handler func(event.Event) bool) {
b.RemoveEventListener(eventType, event.EventPhaseTarget, event.NewHandler(handler, event.EventPhaseTarget))
}

// GetLayoutConstraints 获取布局约束
func (b *BaseComponent) GetLayoutConstraints() *BaseLayoutConstraints {
return b.constraints
}

// SetLayoutConstraints 设置布局约束
func (b *BaseComponent) SetLayoutConstraints(constraints *BaseLayoutConstraints) {
b.constraints = constraints
// 更新布局
if b.layout != nil {
b.Layout()
}
}

// GetEventTarget 返回组件的事件目标
func (c *BaseComponent) GetEventTarget() event.EventTarget {
if c == nil {
return nil
}
return c.eventTarget
}

// EventChildren 返回子组件的事件目标
func (b *BaseComponent) EventChildren() []event.EventTarget {
if b == nil {
return nil
}

b.RLock()
defer b.RUnlock()

if b.children == nil {
return nil
}

children := make([]event.EventTarget, 0, len(b.children))
for _, child := range b.children {
if child == nil {
continue
}
if eventTarget, ok := child.(event.EventTarget); ok && eventTarget != nil {
children = append(children, eventTarget)
}
}
return children
}

// EventParent 返回父组件的事件目标
func (b *BaseComponent) EventParent() event.EventTarget {
if b == nil {
return nil
}

b.RLock()
defer b.RUnlock()

if b.parent == nil {
return nil
}

if eventTarget, ok := b.parent.(event.EventTarget); ok && eventTarget != nil {
return eventTarget
}
return nil
}

// GetLayout 获取布局管理器
func (b *BaseComponent) GetLayout() SimpleLayout {
return b.layout
}

// Equal 比较两个事件目标是否相等
func (b *BaseComponent) Equal(other event.EventTarget) bool {
if other == nil {
return false
}

// 尝试将other转换为*BaseComponent
if otherComponent, ok := other.(*BaseComponent); ok {
return b == otherComponent
}
return false
}

// TargetID 返回事件目标的唯一标识符
func (b *BaseComponent) TargetID() string {
return b.id
}

// AddEventChild 添加事件子组件
func (b *BaseComponent) AddEventChild(child event.EventTarget) {
if b == nil || child == nil {
return
}

b.Lock()
defer b.Unlock()

// 如果子组件也是Component,则通过AddChild添加
if component, ok := child.(Component); ok {
b.AddChild(component)
return
}

// 保eventTarget已初始化
if b.eventTarget == nil {
b.eventTarget = event.NewBaseEventTarget()
}
b.eventTarget.AddEventChild(child)
}

// RemoveEventChild 移除事件子组件
func (b *BaseComponent) RemoveEventChild(child event.EventTarget) {
if b == nil || child == nil {
return
}

b.Lock()
defer b.Unlock()

// 如果子组件也是Component,则通过RemoveChild移除
if component, ok := child.(Component); ok {
b.RemoveChild(component)
return
}

// 确保eventTarget已初始化
if b.eventTarget != nil {
b.eventTarget.RemoveEventChild(child)
}
}

// SetEventParent 设置事件父组件
func (b *BaseComponent) SetEventParent(parent event.EventTarget) {
if b == nil {
return
}

// 如果父组件也是Component,则通过SetParent设置
if component, ok := parent.(Component); ok {
b.SetParent(component)
return
}

// 确保eventTarget已初始化
var target event.EventTarget
func() {
b.Lock()
defer b.Unlock()

if b.eventTarget == nil {
b.eventTarget = event.NewBaseEventTarget()
}
target = b.eventTarget
}()

// 在锁外处理事件目标关系
if target != nil {
target.SetEventParent(parent)
}
}

```

# File: container_test.go

```go
package base

import (
"plants-vs-zombies/internal/core/event"
"reflect"
"sync"
"testing"
)

func TestBaseContainer(t *testing.T) {
t.Run("测试事件处理", func(t *testing.T) {
container := NewBaseContainer()

child1 := NewBaseComponent()
child2 := NewBaseComponent()

container.AddComponent(child1)
container.AddComponent(child2)

eventHandled := false
handler := NewEventHandler(func(evt event.Event) bool {
if evt.Target() == child1.GetEventTarget() && evt.CurrentTarget() == child1.GetEventTarget() {
eventHandled = true
}
return true
})

child1.AddEventListener(event.EventTypeClick, event.EventPhaseTarget, handler, 0)

evt := event.NewBaseEvent(event.EventTypeClick, true)
evt.SetTarget(child1.GetEventTarget())
evt.SetPhase(event.EventPhaseCapturing)
evt.SetCurrentTarget(child1.GetEventTarget())

container.HandleEvent(evt)

if !eventHandled {
t.Error("事件未被正确处理")
}
})

t.Run("测试事件冒泡", func(t *testing.T) {
container := NewBaseContainer()
child := NewBaseComponent()

container.AddComponent(child)

bubbleHandled := false
handler := NewEventHandler(func(evt event.Event) bool {
if evt.Phase() == event.EventPhaseBubbling && evt.CurrentTarget() == container.GetEventTarget() {
bubbleHandled = true
}
return true
})

container.AddEventListener(event.EventTypeClick, event.EventPhaseBubbling, handler, 0)

evt := event.NewBaseEvent(event.EventTypeClick, true)
evt.SetTarget(child.GetEventTarget())
evt.SetPhase(event.EventPhaseCapturing)
evt.SetCurrentTarget(container.GetEventTarget())

container.DispatchEvent(evt)

if !bubbleHandled {
t.Error("事件冒泡未被正确处理")
}
})

t.Run("测试事件传播顺序", func(t *testing.T) {
container := NewBaseContainer()
child := NewBaseComponent()
container.AddComponent(child)

var eventOrder []string
var mu sync.Mutex

captureHandler := NewEventHandler(func(evt event.Event) bool {
if evt.Phase() == event.EventPhaseCapturing && evt.CurrentTarget() == container.GetEventTarget() {
mu.Lock()
eventOrder = append(eventOrder, "container-capture")
mu.Unlock()
}
return false
})
container.AddEventListener(event.EventTypeClick, event.EventPhaseCapturing, captureHandler, 0)

targetHandler := NewEventHandler(func(evt event.Event) bool {
if evt.Phase() == event.EventPhaseTarget && evt.Target() == child.GetEventTarget() && evt.CurrentTarget() == child.GetEventTarget() {
mu.Lock()
eventOrder = append(eventOrder, "child-target")
mu.Unlock()
}
return false
})
child.AddEventListener(event.EventTypeClick, event.EventPhaseTarget, targetHandler, 0)

bubbleHandler := NewEventHandler(func(evt event.Event) bool {
if evt.Phase() == event.EventPhaseBubbling && evt.CurrentTarget() == container.GetEventTarget() {
mu.Lock()
eventOrder = append(eventOrder, "container-bubble")
mu.Unlock()
}
return false
})
container.AddEventListener(event.EventTypeClick, event.EventPhaseBubbling, bubbleHandler, 0)

evt := event.NewBaseEvent(event.EventTypeClick, true)
evt.SetTarget(child.GetEventTarget())
evt.SetPhase(event.EventPhaseCapturing)
evt.SetCurrentTarget(container.GetEventTarget())

container.DispatchEvent(evt)

expected := []string{"container-capture", "child-target", "container-bubble"}
if !reflect.DeepEqual(eventOrder, expected) {
t.Errorf("事件传播顺序错误,期望 %v,得到 %v", expected, eventOrder)
}
})
}

func TestContainerLayout(t *testing.T) {
container := NewBaseContainer()
container.SetBounds(NewBounds(0, 0, 100, 100))

// 创建边距对象
padding := NewMargins(5, 5, 5, 5)
margin := NewMargins(10, 10, 10, 10)

// 设置边距
container.SetPadding(padding) // 直接传递,因为 NewMargins 已经返回指针
container.SetMargin(margin) // 直接传递,因为 NewMargins 已经返回指针

// 验证边距计算
if container.GetPadding().Left != 5 {
t.Errorf("内边距设置错误,期望 5,得到 %v", container.GetPadding().Left)
}

if container.GetMargin().Left != 10 {
t.Errorf("外边距设置错误,期望 10,得到 %v", container.GetMargin().Left)
}
}

func TestContainerChildren(t *testing.T) {
container := NewBaseContainer()
child := NewBaseComponent()

// 测试添加子组件
container.AddComponent(child)
if len(container.GetComponents()) != 1 {
t.Error("添加子组件失败")
}

// 测试移除子组件
container.RemoveComponent(child)
if len(container.GetComponents()) != 0 {
t.Error("移除子组件失败")
}

// 测试清除所有子组件
container.AddComponent(child)
container.Clear()
if len(container.GetComponents()) != 0 {
t.Error("清除子组件失败")
}
}

```

# File: pool.go

```go
package base

import (
"sync"
)

// ComponentPool 组件对象池
type ComponentPool struct {
pool sync.Pool
}

// NewComponentPool 创建新的组件池
func NewComponentPool() *ComponentPool {
return &ComponentPool{
pool: sync.Pool{
New: func() interface{} {
return NewBaseComponent()
},
},
}
}

// Get 从池中获取组件
func (p *ComponentPool) Get() Component {
comp := p.pool.Get().(Component)
comp.Init() // 重新初始化组件
return comp
}

// Put 将组件放回池中
func (p *ComponentPool) Put(comp Component) {
if comp == nil {
return
}

// 清理组件状态
comp.Destroy()

// 重置基本属性
if baseComp, ok := comp.(*BaseComponent); ok {
baseComp.enabled = true
baseComp.visible = true
baseComp.focused = false
baseComp.initialized = false
baseComp.children = make([]Component, 0)
baseComp.parent = nil
baseComp.bounds = NewBounds(0, 0, 0, 0)
baseComp.constraints = NewBaseLayoutConstraints()
baseComp.layout = nil
baseComp.flexible = false
baseComp.flexWeight = 1.0
}

p.pool.Put(comp)
}

// GlobalComponentPool 全局组件池实例
var GlobalComponentPool = NewComponentPool()

// 组件池工具函数

// GetComponent 从全局池获取组件
func GetComponent() Component {
return GlobalComponentPool.Get()
}

// PutComponent 将组件放回全局池
func PutComponent(comp Component) {
GlobalComponentPool.Put(comp)
}

// GetComponents 批量获取组件
func GetComponents(count int) []Component {
components := make([]Component, count)
for i := 0; i < count; i++ {
components[i] = GetComponent()
}
return components
}

// PutComponents 批量回收组件
func PutComponents(components []Component) {
for _, comp := range components {
PutComponent(comp)
}
}
```

# File: layout_test.go

```go
package base

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestLayoutConstraints(t *testing.T) {
t.Run("Validation", func(t *testing.T) {
constraints := NewBaseLayoutConstraints()

// 测试默认值
assert.Equal(t, float64(0), constraints.MinWidth())
assert.Equal(t, float64(-1), constraints.MaxWidth())
assert.Equal(t, float64(0), constraints.MinHeight())
assert.Equal(t, float64(-1), constraints.MaxHeight())

// 测试设置值
constraints.SetMinWidth(100)
constraints.SetMaxWidth(200)
constraints.SetMinHeight(150)
constraints.SetMaxHeight(300)

assert.Equal(t, float64(100), constraints.MinWidth())
assert.Equal(t, float64(200), constraints.MaxWidth())
assert.Equal(t, float64(150), constraints.MinHeight())
assert.Equal(t, float64(300), constraints.MaxHeight())

// 测试验证
assert.NoError(t, constraints.Validate())

// 测试无效值
constraints.SetMinWidth(-1)
assert.Error(t, constraints.Validate())

constraints.SetMinWidth(300)
assert.Error(t, constraints.Validate())
})
}

func TestSimpleFlowLayout(t *testing.T) {
t.Run("HorizontalLayout", func(t *testing.T) {
container := NewBaseComponent()
container.SetBounds(NewBounds(0, 0, 300, 100))

// 添加三个子组件
child1 := NewBaseComponent()
child1.SetBounds(NewBounds(0, 0, 80, 50))
container.AddChild(child1)

child2 := NewBaseComponent()
child2.SetBounds(NewBounds(0, 0, 80, 60))
container.AddChild(child2)

child3 := NewBaseComponent()
child3.SetBounds(NewBounds(0, 0, 80, 40))
container.AddChild(child3)

// 创建水平流式布局
layout := NewSimpleFlowLayout(10, Horizontal)
layout.Layout(container)

// 验证布局结果
assert.Equal(t, float64(0), child1.GetBounds().X())
assert.Equal(t, float64(90), child2.GetBounds().X())
assert.Equal(t, float64(180), child3.GetBounds().X())
})

t.Run("VerticalLayout", func(t *testing.T) {
container := NewBaseComponent()
container.SetBounds(NewBounds(0, 0, 100, 300))

// 添加三个子组件
child1 := NewBaseComponent()
child1.SetBounds(NewBounds(0, 0, 80, 50))
container.AddChild(child1)

child2 := NewBaseComponent()
child2.SetBounds(NewBounds(0, 0, 80, 60))
container.AddChild(child2)

child3 := NewBaseComponent()
child3.SetBounds(NewBounds(0, 0, 80, 40))
container.AddChild(child3)

// 创建垂直流式布局
layout := NewSimpleFlowLayout(10, Vertical)
layout.Layout(container)

// 验证布局结果
assert.Equal(t, float64(0), child1.GetBounds().Y())
assert.Equal(t, float64(60), child2.GetBounds().Y())
assert.Equal(t, float64(130), child3.GetBounds().Y())
})
}

func TestSimpleGridLayout(t *testing.T) {
t.Run("2x2Grid", func(t *testing.T) {
container := NewBaseComponent()
container.SetBounds(NewBounds(0, 0, 200, 200))

// 添加四个子组件
for i := 0; i < 4; i++ {
child := NewBaseComponent()
child.SetBounds(NewBounds(0, 0, 50, 50))
container.AddChild(child)
}

// 创建2x2网格布局
layout := NewSimpleGridLayout(2, 10)
layout.Layout(container)

children := container.Children()

// 验证第一行
assert.Equal(t, float64(0), children[0].GetBounds().X())
assert.Equal(t, float64(0), children[0].GetBounds().Y())
assert.Equal(t, float64(105), children[1].GetBounds().X())
assert.Equal(t, float64(0), children[1].GetBounds().Y())

// 验证第二行
assert.Equal(t, float64(0), children[2].GetBounds().X())
assert.Equal(t, float64(105), children[2].GetBounds().Y())
assert.Equal(t, float64(105), children[3].GetBounds().X())
assert.Equal(t, float64(105), children[3].GetBounds().Y())
})

t.Run("EmptyContainer", func(t *testing.T) {
container := NewBaseComponent()
container.SetBounds(NewBounds(0, 0, 200, 200))

layout := NewSimpleGridLayout(2, 10)
layout.Layout(container)

// 验证空容器不会导致错误
assert.Empty(t, container.Children())
})

t.Run("InvalidColumns", func(t *testing.T) {
container := NewBaseComponent()
container.SetBounds(NewBounds(0, 0, 200, 200))

child := NewBaseComponent()
container.AddChild(child)

layout := NewSimpleGridLayout(0, 10)
layout.Layout(container)

// 验证无效列数不会导致错误
assert.NotPanics(t, func() {
layout.Layout(container)
})
})
}

func BenchmarkLayouts(b *testing.B) {
b.Run("FlowLayout", func(b *testing.B) {
container := NewBaseComponent()
container.SetBounds(NewBounds(0, 0, 1000, 1000))

// 添加100个子组件
for i := 0; i < 100; i++ {
child := NewBaseComponent()
child.SetBounds(NewBounds(0, 0, 50, 50))
container.AddChild(child)
}

layout := NewSimpleFlowLayout(10, Horizontal)

b.ResetTimer()
for i := 0; i < b.N; i++ {
layout.Layout(container)
}
})

b.Run("GridLayout", func(b *testing.B) {
container := NewBaseComponent()
container.SetBounds(NewBounds(0, 0, 1000, 1000))

// 添加100个子组件
for i := 0; i < 100; i++ {
child := NewBaseComponent()
child.SetBounds(NewBounds(0, 0, 50, 50))
container.AddChild(child)
}

layout := NewSimpleGridLayout(10, 10)

b.ResetTimer()
for i := 0; i < b.N; i++ {
layout.Layout(container)
}
})
}

```

# File: layout.go

```go
// Package base provides core UI components and interfaces
package base

import (
"fmt"
)

// Orientation represents component orientation
type Orientation int

const (
// Horizontal orientation arranges components from left to right
Horizontal Orientation = iota
// Vertical orientation arranges components from top to bottom
Vertical
)

// Alignment represents component alignment options
type Alignment int

const (
AlignStart Alignment = iota // Left or top alignment
AlignCenter // Center alignment
AlignEnd // Right or bottom alignment
AlignStretch // Stretch to fill available space
)

// BaseLayoutConstraints defines layout constraints for a component
type BaseLayoutConstraints struct {
minWidth float64
maxWidth float64
minHeight float64
maxHeight float64
orientation Orientation
alignment Alignment
margin Margins
padding Margins
}

// NewBaseLayoutConstraints creates a new BaseLayoutConstraints instance
func NewBaseLayoutConstraints() *BaseLayoutConstraints {
return &BaseLayoutConstraints{
minWidth: 0,
maxWidth: -1, // -1 means no limit
minHeight: 0,
maxHeight: -1,
orientation: Horizontal,
alignment: AlignStart,
margin: Margins{},
padding: Margins{},
}
}

// Validate validates the layout constraints
func (c *BaseLayoutConstraints) Validate() error {
if c.minWidth < 0 {
return fmt.Errorf("minimum width cannot be negative")
}
if c.maxWidth >= 0 && c.maxWidth < c.minWidth {
return fmt.Errorf("maximum width cannot be less than minimum width")
}
if c.minHeight < 0 {
return fmt.Errorf("minimum height cannot be negative")
}
if c.maxHeight >= 0 && c.maxHeight < c.minHeight {
return fmt.Errorf("maximum height cannot be less than minimum height")
}
return nil
}

// Getters and setters
func (c *BaseLayoutConstraints) MinWidth() float64 { return c.minWidth }
func (c *BaseLayoutConstraints) SetMinWidth(width float64) { c.minWidth = width }
func (c *BaseLayoutConstraints) MaxWidth() float64 { return c.maxWidth }
func (c *BaseLayoutConstraints) SetMaxWidth(width float64) { c.maxWidth = width }
func (c *BaseLayoutConstraints) MinHeight() float64 { return c.minHeight }
func (c *BaseLayoutConstraints) SetMinHeight(height float64) { c.minHeight = height }
func (c *BaseLayoutConstraints) MaxHeight() float64 { return c.maxHeight }
func (c *BaseLayoutConstraints) SetMaxHeight(height float64) { c.maxHeight = height }
func (c *BaseLayoutConstraints) Orientation() Orientation { return c.orientation }
func (c *BaseLayoutConstraints) SetOrientation(orientation Orientation) { c.orientation = orientation }
func (c *BaseLayoutConstraints) Alignment() Alignment { return c.alignment }
func (c *BaseLayoutConstraints) SetAlignment(alignment Alignment) { c.alignment = alignment }
func (c *BaseLayoutConstraints) Margin() Margins { return c.margin }
func (c *BaseLayoutConstraints) SetMargin(margin Margins) { c.margin = margin }
func (c *BaseLayoutConstraints) Padding() Margins { return c.padding }
func (c *BaseLayoutConstraints) SetPadding(padding Margins) { c.padding = padding }

// SimpleFlowLayout 实现简单的流式布局
type SimpleFlowLayout struct {
spacing float64
direction Orientation
}

// NewSimpleFlowLayout 创建新的流式布局
func NewSimpleFlowLayout(spacing float64, direction Orientation) *SimpleFlowLayout {
return &SimpleFlowLayout{
spacing: spacing,
direction: direction,
}
}

// Layout 实现流式布局
func (l *SimpleFlowLayout) Layout(container Container) {
if container == nil {
return
}

components := container.GetComponents()
if len(components) == 0 {
return
}

bounds := container.GetBounds()
if bounds == nil {
return
}

// 获取容器的可用空间
x := bounds.X()
y := bounds.Y()
maxWidth := bounds.Width()

// 当前行的最大高度
var lineHeight float64
startX := x

// 布局每个组件
for _, comp := range components {
if !comp.IsVisible() {
continue
}

compBounds := comp.GetBounds()
if compBounds == nil {
continue
}

if l.direction == Horizontal {
// 水平布局
if x > startX && x+compBounds.Width() > bounds.X()+maxWidth {
x = startX
y += lineHeight + l.spacing
lineHeight = 0
}

// 设置组件位置
compBounds.SetX(x)
compBounds.SetY(y)
comp.SetBounds(compBounds)

// 更新位置和行高
x += compBounds.Width() + l.spacing
if compBounds.Height() > lineHeight {
lineHeight = compBounds.Height()
}
} else {
// 垂直布局
compBounds.SetX(x)
compBounds.SetY(y)
comp.SetBounds(compBounds)

// 更新位置
y += compBounds.Height() + l.spacing
}
}
}

// SimpleGridLayout 实现简单的网格布局
type SimpleGridLayout struct {
columns int
spacing float64
}

// NewSimpleGridLayout 创建新的网格布局
func NewSimpleGridLayout(columns int, spacing float64) *SimpleGridLayout {
return &SimpleGridLayout{
columns: columns,
spacing: spacing,
}
}

// Layout 实现网格布局
func (l *SimpleGridLayout) Layout(container Container) {
if container == nil || l.columns <= 0 {
return
}

components := container.GetComponents()
if len(components) == 0 {
return
}

bounds := container.GetBounds()
if bounds == nil {
return
}

// 计算单元格大小
cellWidth := (bounds.Width() - float64(l.columns-1)*l.spacing) / float64(l.columns)
cellHeight := cellWidth // 默认使用正方形单元格

// 布局每个组件
row := 0
col := 0
x := bounds.X()
y := bounds.Y()

for _, comp := range components {
if !comp.IsVisible() {
continue
}

compBounds := comp.GetBounds()
if compBounds == nil {
continue
}

// 设置组件位置和大小
compBounds.SetX(x + float64(col)*(cellWidth+l.spacing))
compBounds.SetY(y + float64(row)*(cellHeight+l.spacing))
compBounds.SetWidth(cellWidth)
compBounds.SetHeight(cellHeight)
comp.SetBounds(compBounds)

// 移动到下一个位置
col++
if col >= l.columns {
col = 0
row++
}
}
}

```

# File: interactive.go

```go
package base

import (
"plants-vs-zombies/internal/core/event"
)

// InteractiveComponent 提供可交互组件的基本实现
type InteractiveComponent struct {
*BaseComponent
hover bool
pressed bool
focused bool
}

// NewInteractiveComponent 创建新的可交互组件
func NewInteractiveComponent() *InteractiveComponent {
i := &InteractiveComponent{
BaseComponent: NewBaseComponent(),
hover: false,
pressed: false,
focused: false,
}
return i
}

// GetEventTarget 获取事件目标
func (i *InteractiveComponent) GetEventTarget() event.EventTarget {
return i
}

// EventParent 获取事件父组件
func (i *InteractiveComponent) EventParent() event.EventTarget {
if i.parent == nil {
return nil
}
if target, ok := i.parent.(event.EventTarget); ok {
return target
}
return nil
}

// EventChildren 获取子组件列表
func (i *InteractiveComponent) EventChildren() []event.EventTarget {
var children []event.EventTarget
for _, child := range i.children {
if target, ok := child.(event.EventTarget); ok {
children = append(children, target)
}
}
return children
}

// AddEventChild 添加子组件
func (i *InteractiveComponent) AddEventChild(child event.EventTarget) {
if comp, ok := child.(Component); ok {
i.AddChild(comp)
}
}

// RemoveEventChild 移除子组件
func (i *InteractiveComponent) RemoveEventChild(child event.EventTarget) {
if comp, ok := child.(Component); ok {
i.RemoveChild(comp)
}
}

// AddEventListener 添加事件监听器
func (i *InteractiveComponent) AddEventListener(eventType event.EventType, phase event.EventPhase, handler event.Handler, priority int) {
i.BaseComponent.AddEventListener(eventType, phase, handler, priority)
}

// RemoveEventListener 移除事件监听器
func (i *InteractiveComponent) RemoveEventListener(eventType event.EventType, phase event.EventPhase, handler event.Handler) {
i.BaseComponent.RemoveEventListener(eventType, phase, handler)
}

// HandleEvent 处理事件
func (i *InteractiveComponent) HandleEvent(evt event.Event) bool {
if !i.IsEnabled() || !i.IsVisible() {
return false
}

// 设置当前目标
evt.SetCurrentTarget(i)

// 处理鼠标事件
if mouseEvt, ok := evt.(*event.MouseEvent); ok {
// 检查鼠标是否在组件范围内
inBounds := i.GetBounds().Contains(mouseEvt.GetX(), mouseEvt.GetY())

switch evt.Type() {
case event.EventTypeMouseMove:
// 处理鼠标进入/离开
if inBounds && !i.hover {
i.hover = true
enterEvt := event.NewBaseEvent(event.EventTypeMouseEnter, true)
enterEvt.SetTarget(i)
enterEvt.SetPhase(event.EventPhaseTarget)
i.DispatchEvent(enterEvt)
i.BaseComponent.Layout()
} else if !inBounds && i.hover {
i.hover = false
leaveEvt := event.NewBaseEvent(event.EventTypeMouseLeave, true)
leaveEvt.SetTarget(i)
leaveEvt.SetPhase(event.EventPhaseTarget)
i.DispatchEvent(leaveEvt)
i.BaseComponent.Layout()
}

case event.EventTypeMouseButtonDown:
if inBounds {
i.pressed = true
// 设置焦点
if !i.focused {
i.SetFocused(true)
}
i.BaseComponent.Layout()
}

case event.EventTypeMouseButtonUp:
wasPressed := i.pressed
i.pressed = false

if inBounds {
i.BaseComponent.Layout()
// 如果之前是按下状态,触发点击事件
if wasPressed {
clickEvt := event.NewBaseEvent(event.EventTypeClick, true)
clickEvt.SetTarget(i)
clickEvt.SetPhase(event.EventPhaseTarget)
i.DispatchEvent(clickEvt)
}
}
}
}

// 根据事件阶段处理
switch evt.Phase() {
case event.EventPhaseCapturing:
// 捕获阶段:从根到目标的传播
return i.BaseComponent.HandleEvent(evt)

case event.EventPhaseTarget:
// 目标阶段:在目标上触发事件
key := EventListenerKey{
Type: evt.Type(),
Phase: event.EventPhaseTarget,
}
i.callEventListeners(key, evt)

// 如果事件可以冒泡且有父组件,切换到冒泡阶段并继续传播
if evt.Bubbles() && !evt.IsPropagationStopped() {
evt.SetPhase(event.EventPhaseBubbling)
if parent := i.EventParent(); parent != nil {
return parent.HandleEvent(evt)
}
}
return !evt.IsPropagationStopped()

case event.EventPhaseBubbling:
// 冒泡阶段:处理当前组件的监听器
key := EventListenerKey{
Type: evt.Type(),
Phase: event.EventPhaseTarget,
}
i.callEventListeners(key, evt)

// 继续向上冒泡
if !evt.IsPropagationStopped() {
if parent := i.EventParent(); parent != nil {
return parent.HandleEvent(evt)
}
}
return !evt.IsPropagationStopped()

default:
// 如果没有指定阶段,从目标阶段开始
evt.SetPhase(event.EventPhaseTarget)
return i.HandleEvent(evt)
}
}

// SetFocused 设置焦点状态
func (i *InteractiveComponent) SetFocused(focused bool) {
if i.focused == focused {
return
}

i.focused = focused

// 创建焦点事件
var evt event.Event
if focused {
evt = event.NewBaseEvent(event.EventTypeFocusGain, true)
} else {
evt = event.NewBaseEvent(event.EventTypeFocusLoss, true)
}

// 设置事件目标
evt.SetTarget(i)
evt.SetPhase(event.EventPhaseTarget)

// 分发事件
i.DispatchEvent(evt)

// 更新布局
i.BaseComponent.Layout()
}

// IsFocused 获取焦点状态
func (i *InteractiveComponent) IsFocused() bool {
return i.focused
}

// IsHovered 获取悬停状态
func (i *InteractiveComponent) IsHovered() bool {
return i.hover
}

// IsPressed 获取按下状态
func (i *InteractiveComponent) IsPressed() bool {
return i.pressed
}

// SetEnabled 设置是否启用
func (i *InteractiveComponent) SetEnabled(enabled bool) {
if i.BaseComponent.IsEnabled() == enabled {
return
}

i.BaseComponent.SetEnabled(enabled)
if !enabled {
i.hover = false
i.pressed = false
if i.focused {
i.SetFocused(false)
}
}
i.BaseComponent.Layout()
}

// SetVisible 设置是否可见
func (i *InteractiveComponent) SetVisible(visible bool) {
if i.BaseComponent.IsVisible() == visible {
return
}

i.BaseComponent.SetVisible(visible)
if !visible {
i.hover = false
i.pressed = false
if i.focused {
i.SetFocused(false)
}
}
i.BaseComponent.Layout()
}

// Update 更新组件状态
func (c *InteractiveComponent) Update() error {
if err := c.BaseComponent.Update(); err != nil {
return err
}

// 更新悬停状态
if c.IsEnabled() && c.IsVisible() {
// TODO: 获取当前鼠标位置并更新悬停状态
}

return nil
}

```

# File: bounds.go

```go
package base

import (
"fmt"
)

// BaseBounds 定义组件的位置和大小
type BaseBounds struct {
x float64
y float64
width float64
height float64
}

// NewBounds 创建新的边界对象
func NewBounds(x, y, width, height float64) *BaseBounds {
return &BaseBounds{
x: x,
y: y,
width: width,
height: height,
}
}

// X 返回 x 坐标
func (b *BaseBounds) X() float64 { return b.x }

// Y 返回 y 坐标
func (b *BaseBounds) Y() float64 { return b.y }

// Width 返回宽度
func (b *BaseBounds) Width() float64 { return b.width }

// Height 返回高度
func (b *BaseBounds) Height() float64 { return b.height }

// SetX 设置 x 坐标
func (b *BaseBounds) SetX(x float64) { b.x = x }

// SetY 设置 y 坐标
func (b *BaseBounds) SetY(y float64) { b.y = y }

// SetWidth 设置宽度
func (b *BaseBounds) SetWidth(width float64) { b.width = width }

// SetHeight 设置高度
func (b *BaseBounds) SetHeight(height float64) { b.height = height }

// Contains 检查点是否在边界内
func (b *BaseBounds) Contains(x, y float64) bool {
return x >= b.x && x <= b.x+b.width &&
y >= b.y && y <= b.y+b.height
}

// Intersects 检查是否与另一个边界相交
func (b *BaseBounds) Intersects(other *BaseBounds) bool {
if other == nil {
return false
}

// 两个矩形不相交的条件:
// 1. 一个在另一个的左边
// 2. 一个在另一个的右边
// 3. 一个在另一个的上边
// 4. 一个在另一个的下边
return !(b.x >= other.x+other.width || // 当前矩形在另一个的右边
b.x+b.width <= other.x || // 当前矩形在另一个的左边
b.y >= other.y+other.height || // 当前矩形在另一个的下边
b.y+b.height <= other.y) // 当前矩形在另一个的上边
}

// Clone 创建边界的副本
func (b *BaseBounds) Clone() *BaseBounds {
return NewBounds(b.x, b.y, b.width, b.height)
}

// String 返回边界的字符串表示
func (b *BaseBounds) String() string {
return fmt.Sprintf("Bounds(x:%.1f, y:%.1f, w:%.1f, h:%.1f)",
b.x, b.y, b.width, b.height)
}

```

# File: interfaces.go

```go
package base

import (
"plants-vs-zombies/internal/core/event"
"github.com/hajimehoshi/ebiten/v2"
)

// Component 定义了基本的UI组件接口
type Component interface {
// 基本属性
IsEnabled() bool
SetEnabled(bool)
IsVisible() bool
SetVisible(bool)
IsFocused() bool
SetFocused(bool)

// 布局相关
GetBounds() *BaseBounds
SetBounds(*BaseBounds)
GetLayoutConstraints() *BaseLayoutConstraints
SetLayoutConstraints(*BaseLayoutConstraints)
Layout()
SetLayout(SimpleLayout)

// 组件树操作
Parent() Component
SetParent(Component)
Children() []Component
AddChild(Component)
RemoveChild(Component)
AddComponent(Component)
RemoveComponent(Component)
GetComponents() []Component

// 生命周期
Init()
Update() error
Draw(*ebiten.Image)
Destroy()

// 事件系统 - 修改为与 EventTarget 接口一致
GetEventTarget() event.EventTarget
HandleEvent(event.Event) bool
DispatchEvent(event.Event) bool
// 修改事件监听器方法签名
AddEventListener(eventType event.EventType, phase event.EventPhase, handler event.Handler, priority int)
RemoveEventListener(eventType event.EventType, phase event.EventPhase, handler event.Handler)
EmitEvent(eventType event.EventType)
// 保留便捷方法
OnEvent(eventType event.EventType, handler func(event.Event) bool)
OffEvent(eventType event.EventType, handler func(event.Event) bool)
}

// Container 定义了容器组件的接口
type Container interface {
Component
Clear()
GetPadding() *Margins
SetPadding(*Margins)
GetMargin() *Margins
SetMargin(*Margins)
}

// Interactive 定义了可交互组件的接口
type Interactive interface {
Component
IsHovered() bool
SetHovered(bool)
IsPressed() bool
SetPressed(bool)
}

// SimpleLayout 定义了简单布局接口
type SimpleLayout interface {
Layout(container Container)
}

```

# File: debug_test.go

```go
package base

import (
"image/color"
"testing"

"github.com/hajimehoshi/ebiten/v2"
"github.com/stretchr/testify/assert"
)

func TestLayoutDebugger(t *testing.T) {
t.Run("NewLayoutDebugger", func(t *testing.T) {
debugger := NewLayoutDebugger()
assert.NotNil(t, debugger, "NewLayoutDebugger should not return nil")
assert.False(t, debugger.IsEnabled(), "Debugger should be disabled by default")
assert.Equal(t, color.RGBA{R: 255, G: 0, B: 0, A: 128}, debugger.color, "Default color should be red with 50% alpha")
})

t.Run("Enable/Disable", func(t *testing.T) {
debugger := NewLayoutDebugger()

debugger.SetEnabled(true)
assert.True(t, debugger.IsEnabled(), "Debugger should be enabled")

debugger.SetEnabled(false)
assert.False(t, debugger.IsEnabled(), "Debugger should be disabled")
})

t.Run("SetColor", func(t *testing.T) {
debugger := NewLayoutDebugger()
testColor := color.RGBA{R: 0, G: 255, B: 0, A: 255}

debugger.SetColor(testColor)
assert.Equal(t, testColor, debugger.color, "Color should be updated")
})

t.Run("DrawDebugInfo", func(t *testing.T) {
debugger := NewLayoutDebugger()
screen := ebiten.NewImage(100, 100)
component := NewBaseComponent()
component.SetBounds(NewBounds(10, 10, 80, 80))

// Test when disabled
debugger.SetEnabled(false)
debugger.DrawDebugInfo(screen, component)
// No assertions needed as disabled debugger shouldn't draw anything

// Test when enabled
debugger.SetEnabled(true)
debugger.DrawDebugInfo(screen, component)
// Visual output testing would require image comparison
})

t.Run("DrawLayoutConstraints", func(t *testing.T) {
debugger := NewLayoutDebugger()
screen := ebiten.NewImage(100, 100)
component := NewBaseComponent()
component.SetBounds(NewBounds(10, 10, 80, 80))

constraints := NewBaseLayoutConstraints()
constraints.SetMinWidth(50)
constraints.SetMinHeight(50)
constraints.SetMaxWidth(100)
constraints.SetMaxHeight(100)
component.SetLayoutConstraints(constraints)

// Test when disabled
debugger.SetEnabled(false)
debugger.DrawLayoutConstraints(screen, component)
// No assertions needed as disabled debugger shouldn't draw anything

// Test when enabled
debugger.SetEnabled(true)
debugger.DrawLayoutConstraints(screen, component)
// Visual output testing would require image comparison
})

t.Run("Container Debug Info", func(t *testing.T) {
debugger := NewLayoutDebugger()
screen := ebiten.NewImage(200, 200)
container := NewBaseContainer()
container.SetBounds(NewBounds(0, 0, 200, 200))

child1 := NewBaseComponent()
child1.SetBounds(NewBounds(10, 10, 80, 80))
container.AddComponent(child1)

child2 := NewBaseComponent()
child2.SetBounds(NewBounds(100, 100, 80, 80))
container.AddComponent(child2)

debugger.SetEnabled(true)
debugger.DrawDebugInfo(screen, container)
// Visual output testing would require image comparison
})
}

func TestComponentBoundsOverlap(t *testing.T) {
t.Run("Overlapping Components", func(t *testing.T) {
comp1 := NewBaseComponent()
comp2 := NewBaseComponent()

comp1.SetBounds(NewBounds(0, 0, 100, 100))
comp2.SetBounds(NewBounds(50, 50, 100, 100))

bounds1 := comp1.GetBounds()
bounds2 := comp2.GetBounds()

assert.True(t, bounds1.Intersects(bounds2), "Components should overlap")
})

t.Run("Non-overlapping Components", func(t *testing.T) {
comp1 := NewBaseComponent()
comp2 := NewBaseComponent()

comp1.SetBounds(NewBounds(0, 0, 100, 100))
comp2.SetBounds(NewBounds(150, 150, 100, 100))

bounds1 := comp1.GetBounds()
bounds2 := comp2.GetBounds()

assert.False(t, bounds1.Intersects(bounds2), "Components should not overlap")
})

t.Run("Adjacent Components", func(t *testing.T) {
comp1 := NewBaseComponent()
comp2 := NewBaseComponent()

comp1.SetBounds(NewBounds(0, 0, 100, 100))
comp2.SetBounds(NewBounds(100, 0, 100, 100))

bounds1 := comp1.GetBounds()
bounds2 := comp2.GetBounds()

assert.False(t, bounds1.Intersects(bounds2), "Adjacent components should not overlap")
})

t.Run("Contained Components", func(t *testing.T) {
comp1 := NewBaseComponent()
comp2 := NewBaseComponent()

comp1.SetBounds(NewBounds(0, 0, 100, 100))
comp2.SetBounds(NewBounds(25, 25, 50, 50))

bounds1 := comp1.GetBounds()
bounds2 := comp2.GetBounds()

assert.True(t, bounds1.Intersects(bounds2), "Contained components should overlap")
})
}

```

# File: types.go

```go
package base

import (
"sync"
)

// Point represents a 2D point with x and y coordinates
type Point struct {
x float64
y float64
}

// NewPoint creates a new Point
func NewPoint(x, y float64) Point {
return Point{x: x, y: y}
}

// X returns the x coordinate
func (p Point) X() float64 {
return p.x
}

// Y returns the y coordinate
func (p Point) Y() float64 {
return p.y
}

// SetX sets the x coordinate
func (p *Point) SetX(x float64) {
p.x = x
}

// SetY sets the y coordinate
func (p *Point) SetY(y float64) {
p.y = y
}

// Equals returns true if the points are equal
func (p Point) Equals(other Point) bool {
return p.x == other.x && p.y == other.y
}

// Direction represents a layout direction
type Direction int

const (
// DirectionHorizontal represents horizontal direction
DirectionHorizontal Direction = iota
// DirectionVertical represents vertical direction
DirectionVertical
)

// Size represents a 2D size with width and height
type Size struct {
width float64
height float64
}

// NewSize creates a new Size
func NewSize(width, height float64) Size {
return Size{width: width, height: height}
}

// Width returns the width
func (s Size) Width() float64 {
return s.width
}

// Height returns the height
func (s Size) Height() float64 {
return s.height
}

// SetWidth sets the width
func (s *Size) SetWidth(width float64) {
s.width = width
}

// SetHeight sets the height
func (s *Size) SetHeight(height float64) {
s.height = height
}

// Equals returns true if the sizes are equal
func (s Size) Equals(other Size) bool {
return s.width == other.width && s.height == other.height
}

// Color represents an RGBA color
type Color struct {
r, g, b, a float64
}

// NewColor creates a new Color instance
func NewColor(r, g, b, a float64) Color {
return Color{r: r, g: g, b: b, a: a}
}

// R returns the red component
func (c Color) R() float64 {
return c.r
}

// G returns the green component
func (c Color) G() float64 {
return c.g
}

// B returns the blue component
func (c Color) B() float64 {
return c.b
}

// A returns the alpha component
func (c Color) A() float64 {
return c.a
}

// SetR sets the red component
func (c *Color) SetR(r float64) {
c.r = r
}

// SetG sets the green component
func (c *Color) SetG(g float64) {
c.g = g
}

// SetB sets the blue component
func (c *Color) SetB(b float64) {
c.b = b
}

// SetA sets the alpha component
func (c *Color) SetA(a float64) {
c.a = a
}

// Equals returns true if the colors are equal
func (c Color) Equals(other Color) bool {
return c.r == other.r && c.g == other.g && c.b == other.b && c.a == other.a
}

// 添加 ComponentSet 类型,用于存储已处理的组件
type ComponentSet struct {
sync.RWMutex
components map[Component]struct{}
}

func NewComponentSet() *ComponentSet {
return &ComponentSet{
components: make(map[Component]struct{}),
}
}

func (cs *ComponentSet) Add(c Component) {
cs.Lock()
defer cs.Unlock()
cs.components[c] = struct{}{}
}

func (cs *ComponentSet) Contains(c Component) bool {
cs.RLock()
defer cs.RUnlock()
_, exists := cs.components[c]
return exists
}

func (cs *ComponentSet) Clear() {
cs.Lock()
defer cs.Unlock()
cs.components = make(map[Component]struct{})
}

func (cs *ComponentSet) Remove(c Component) {
cs.Lock()
defer cs.Unlock()
delete(cs.components, c)
}

func (cs *ComponentSet) Size() int {
cs.RLock()
defer cs.RUnlock()
return len(cs.components)
}

func (cs *ComponentSet) ForEach(fn func(Component)) {
cs.RLock()
defer cs.RUnlock()
for c := range cs.components {
fn(c)
}
}

// Rect 定义矩形接口
type Rect interface {
X() float64
Y() float64
Width() float64
Height() float64
SetX(x float64)
SetY(y float64)
SetWidth(width float64)
SetHeight(height float64)
Contains(x, y float64) bool
Intersects(other Rect) bool
Clone() Rect
}

// BaseRect 提供矩形的基本实现
type BaseRect struct {
x, y, width, height float64
}

func (r *BaseRect) X() float64 { return r.x }
func (r *BaseRect) Y() float64 { return r.y }
func (r *BaseRect) Width() float64 { return r.width }
func (r *BaseRect) Height() float64 { return r.height }
func (r *BaseRect) SetX(x float64) { r.x = x }
func (r *BaseRect) SetY(y float64) { r.y = y }
func (r *BaseRect) SetWidth(width float64) { r.width = width }
func (r *BaseRect) SetHeight(height float64) { r.height = height }

func (r *BaseRect) Contains(x, y float64) bool {
return x >= r.x && x <= r.x+r.width &&
y >= r.y && y <= r.y+r.height
}

func (r *BaseRect) Intersects(other Rect) bool {
return !(other.X() > r.x+r.width ||
other.X()+other.Width() < r.x ||
other.Y() > r.y+r.height ||
other.Y()+other.Height() < r.y)
}

func (r *BaseRect) Clone() Rect {
return &BaseRect{
x: r.x,
y: r.y,
width: r.width,
height: r.height,
}
}

// Layout 接口定义
type Layout interface {
Layout(container Container)
}

```

# File: event.go

```go
package base

import (
"sync"
"plants-vs-zombies/internal/core/event"
)

// EventEmitter 定义事件发射器接口
type EventEmitter interface {
// 添加事件监听器
AddListener(eventType event.EventType, handler event.Handler)
// 移除事件监听器
RemoveListener(eventType event.EventType, handler event.Handler)
// 发送事件
EmitEvent(evt event.Event)
}

// BaseEventEmitter 提供事件发射器的基本实现
type BaseEventEmitter struct {
eventTarget *event.BaseEventTarget
mu sync.RWMutex
}

// NewBaseEventEmitter 创建新的事件发射器
func NewBaseEventEmitter() *BaseEventEmitter {
return &BaseEventEmitter{
eventTarget: event.NewBaseEventTarget(),
}
}

// AddListener 添加事件监听器
func (e *BaseEventEmitter) AddListener(eventType event.EventType, handler event.Handler) {
e.mu.Lock()
defer e.mu.Unlock()
e.eventTarget.AddEventListener(eventType, event.EventPhaseTarget, handler, event.PriorityNormal)
}

// RemoveListener 移除事件监听器
func (e *BaseEventEmitter) RemoveListener(eventType event.EventType, handler event.Handler) {
e.mu.Lock()
defer e.mu.Unlock()
e.eventTarget.RemoveEventListener(eventType, event.EventPhaseTarget, handler)
}

// EmitEvent 发送事件
func (e *BaseEventEmitter) EmitEvent(evt event.Event) {
e.mu.RLock()
defer e.mu.RUnlock()
e.eventTarget.DispatchEvent(evt)
}

// AddEventHandler 添加事件处理器(带优先级)
func (e *BaseEventEmitter) AddEventHandler(eventType event.EventType, handler event.Handler, priority int) {
e.mu.Lock()
defer e.mu.Unlock()
e.eventTarget.AddEventListener(eventType, event.EventPhaseTarget, handler, priority)
}

// RemoveEventHandler 移除事件处理器
func (e *BaseEventEmitter) RemoveEventHandler(eventType event.EventType, handler event.Handler) {
e.mu.Lock()
defer e.mu.Unlock()
e.eventTarget.RemoveEventListener(eventType, event.EventPhaseTarget, handler)
}

// DispatchEvent 分发事件
func (e *BaseEventEmitter) DispatchEvent(evt event.Event) bool {
e.mu.RLock()
defer e.mu.RUnlock()

if evt == nil || e.eventTarget == nil {
return false
}

// 设置事件目标
if evt.Target() == nil {
evt.SetTarget(e.eventTarget)
}
evt.SetCurrentTarget(e.eventTarget)

// 先执行捕获阶段
if evt.Bubbles() {
e.eventTarget.AddEventListener(evt.Type(), event.EventPhaseCapturing,
event.HandlerFunc(func(e event.Event) bool {
return true
}), event.PriorityNormal)
e.eventTarget.DispatchEvent(evt)
}

// 执行目标阶段
handled := e.eventTarget.DispatchEvent(evt)

// 最后执行冒泡阶段
if evt.Bubbles() && !handled {
e.eventTarget.AddEventListener(evt.Type(), event.EventPhaseBubbling,
event.HandlerFunc(func(e event.Event) bool {
return true
}), event.PriorityNormal)
handled = e.eventTarget.DispatchEvent(evt)
}

return handled
}

// EventHandler 实现 event.Handler 接口的事件处理器
type EventHandler struct {
id int64
phase event.EventPhase
handler func(event.Event) bool
}

// NewEventHandler 创建新的事件处理器
func NewEventHandler(handler func(event.Event) bool) *EventHandler {
return &EventHandler{
id: generateHandlerID(),
phase: event.EventPhaseTarget,
handler: handler,
}
}

// GetID 实现 Handler 接口
func (h *EventHandler) GetID() int64 {
return h.id
}

// GetPhase 实现 Handler 接口
func (h *EventHandler) GetPhase() event.EventPhase {
return h.phase
}

// SetPhase 设置事件处理阶段
func (h *EventHandler) SetPhase(phase event.EventPhase) {
h.phase = phase
}

// HandleEvent 实现 Handler 接口
func (h *EventHandler) HandleEvent(evt event.Event) bool {
return h.handler(evt)
}

var handlerIDCounter int64
var handlerIDMutex sync.Mutex

func generateHandlerID() int64 {
handlerIDMutex.Lock()
defer handlerIDMutex.Unlock()
handlerIDCounter++
return handlerIDCounter
}
```

# File: types_test.go

```go
package base

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestBounds(t *testing.T) {
t.Run("Basic bounds operations", func(t *testing.T) {
bounds := NewBounds(10, 20, 100, 200)

// Test getters
assert.Equal(t, float64(10), bounds.X())
assert.Equal(t, float64(20), bounds.Y())
assert.Equal(t, float64(100), bounds.Width())
assert.Equal(t, float64(200), bounds.Height())

// Test setters
bounds.SetX(30)
bounds.SetY(40)
bounds.SetWidth(150)
bounds.SetHeight(250)

assert.Equal(t, float64(30), bounds.X())
assert.Equal(t, float64(40), bounds.Y())
assert.Equal(t, float64(150), bounds.Width())
assert.Equal(t, float64(250), bounds.Height())
})

t.Run("Contains point", func(t *testing.T) {
bounds := NewBounds(10, 20, 100, 200)

// Test points inside bounds
assert.True(t, bounds.Contains(15, 25))
assert.True(t, bounds.Contains(50, 100))
assert.True(t, bounds.Contains(109, 219))

// Test points outside bounds
assert.False(t, bounds.Contains(5, 25))
assert.False(t, bounds.Contains(15, 15))
assert.False(t, bounds.Contains(111, 100))
assert.False(t, bounds.Contains(50, 221))
})

t.Run("Bounds intersection", func(t *testing.T) {
bounds1 := NewBounds(10, 20, 100, 200)

bounds2 := NewBounds(50, 60, 100, 200)
bounds3 := NewBounds(200, 300, 100, 200)

// Test intersecting bounds
assert.True(t, bounds1.Intersects(bounds2))
assert.True(t, bounds2.Intersects(bounds1))

// Test non-intersecting bounds
assert.False(t, bounds1.Intersects(bounds3))
assert.False(t, bounds3.Intersects(bounds1))
})
}

func TestPoint(t *testing.T) {
t.Run("Basic point operations", func(t *testing.T) {
point := NewPoint(10, 20)

// Test getters
assert.Equal(t, float64(10), point.X())
assert.Equal(t, float64(20), point.Y())

// Test setters
point.SetX(30)
point.SetY(40)
assert.Equal(t, float64(30), point.X())
assert.Equal(t, float64(40), point.Y())
})

t.Run("Point comparison", func(t *testing.T) {
point1 := NewPoint(10, 20)
point2 := NewPoint(10, 20)
point3 := NewPoint(30, 40)

assert.True(t, point1.Equals(point2))
assert.True(t, point2.Equals(point1))
assert.False(t, point1.Equals(point3))
assert.False(t, point3.Equals(point1))
})
}

func TestSize(t *testing.T) {
t.Run("Basic size operations", func(t *testing.T) {
size := NewSize(100, 200)

// Test getters
assert.Equal(t, float64(100), size.Width())
assert.Equal(t, float64(200), size.Height())

// Test setters
size.SetWidth(150)
size.SetHeight(250)
assert.Equal(t, float64(150), size.Width())
assert.Equal(t, float64(250), size.Height())
})

t.Run("Size comparison", func(t *testing.T) {
size1 := NewSize(100, 200)
size2 := NewSize(100, 200)
size3 := NewSize(150, 250)

assert.True(t, size1.Equals(size2))
assert.True(t, size2.Equals(size1))
assert.False(t, size1.Equals(size3))
assert.False(t, size3.Equals(size1))
})
}

func TestMargins(t *testing.T) {
t.Run("Basic margins operations", func(t *testing.T) {
margins := NewMargins(10, 20, 30, 40)

// Test values
assert.Equal(t, float64(10), margins.Top)
assert.Equal(t, float64(20), margins.Right)
assert.Equal(t, float64(30), margins.Bottom)
assert.Equal(t, float64(40), margins.Left)

// Test spacing calculations
assert.Equal(t, float64(60), margins.GetHorizontalSpacing()) // Left + Right
assert.Equal(t, float64(40), margins.GetVerticalSpacing()) // Top + Bottom
})

t.Run("String representation", func(t *testing.T) {
margins := NewMargins(10, 20, 30, 40)
expected := "Margins(T:10.0 R:20.0 B:30.0 L:40.0)"
assert.Equal(t, expected, margins.String())
})
}

func TestColor(t *testing.T) {
t.Run("Basic color operations", func(t *testing.T) {
color := NewColor(1.0, 0.5, 0.25, 0.75)

// Test getters
assert.Equal(t, float64(1.0), color.R())
assert.Equal(t, float64(0.5), color.G())
assert.Equal(t, float64(0.25), color.B())
assert.Equal(t, float64(0.75), color.A())

// Test setters
color.SetR(0.8)
color.SetG(0.6)
color.SetB(0.4)
color.SetA(0.9)

assert.Equal(t, float64(0.8), color.R())
assert.Equal(t, float64(0.6), color.G())
assert.Equal(t, float64(0.4), color.B())
assert.Equal(t, float64(0.9), color.A())
})

t.Run("Color comparison", func(t *testing.T) {
color1 := NewColor(1.0, 0.5, 0.25, 0.75)
color2 := NewColor(1.0, 0.5, 0.25, 0.75)
color3 := NewColor(0.8, 0.6, 0.4, 0.9)

assert.True(t, color1.Equals(color2))
assert.True(t, color2.Equals(color1))
assert.False(t, color1.Equals(color3))
assert.False(t, color3.Equals(color1))
})
}

```

# File: debug.go

```go
package base

import (
"fmt"
"image/color"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)

// LayoutDebugger 提供UI布局调试功能
type LayoutDebugger struct {
enabled bool
color color.Color
}

// NewLayoutDebugger 创建新的布局调试器
func NewLayoutDebugger() *LayoutDebugger {
return &LayoutDebugger{
enabled: false,
color: color.RGBA{R: 255, G: 0, B: 0, A: 128},
}
}

// SetEnabled 启用或禁用调试器
func (d *LayoutDebugger) SetEnabled(enabled bool) {
d.enabled = enabled
}

// IsEnabled 返回调试器是否启用
func (d *LayoutDebugger) IsEnabled() bool {
return d.enabled
}

// SetColor 设置调试颜色
func (d *LayoutDebugger) SetColor(c color.Color) {
d.color = c
}

// DrawDebugInfo 绘制组件的调试信息
func (d *LayoutDebugger) DrawDebugInfo(screen *ebiten.Image, component Component) {
if !d.enabled {
return
}

bounds := component.GetBounds()
if bounds == nil {
return
}

// 绘制组件边界
ebitenutil.DrawRect(screen, bounds.X(), bounds.Y(), bounds.Width(), bounds.Height(), d.color)

// 绘制组件信息
info := fmt.Sprintf("Pos: (%.1f, %.1f)\nSize: %.1fx%.1f",
bounds.X(), bounds.Y(), bounds.Width(), bounds.Height())
ebitenutil.DebugPrintAt(screen, info, int(bounds.X()), int(bounds.Y()))

// 如果是容器,绘制子组件的调试信息
if container, ok := component.(Container); ok {
for _, child := range container.GetComponents() {
d.DrawDebugInfo(screen, child)
}
}
}

// DrawLayoutConstraints 绘制布局约束的调试信息
func (d *LayoutDebugger) DrawLayoutConstraints(screen *ebiten.Image, component Component) {
if !d.enabled {
return
}

constraints := component.GetLayoutConstraints()
if constraints == nil {
return
}

bounds := component.GetBounds()
if bounds == nil {
return
}

// 绘制最小/最大尺寸信息
info := fmt.Sprintf("Min: %.1fx%.1f\nMax: %.1fx%.1f",
constraints.MinWidth(), constraints.MinHeight(),
constraints.MaxWidth(), constraints.MaxHeight())
ebitenutil.DebugPrintAt(screen, info,
int(bounds.X()), int(bounds.Y()+bounds.Height()))

// 绘制边距信息
margin := constraints.Margin()
padding := constraints.Padding()
marginInfo := fmt.Sprintf("Margin: T:%.1f R:%.1f B:%.1f L:%.1f",
margin.Top, margin.Right, margin.Bottom, margin.Left)
paddingInfo := fmt.Sprintf("Padding: T:%.1f R:%.1f B:%.1f L:%.1f",
padding.Top, padding.Right, padding.Bottom, padding.Left)

ebitenutil.DebugPrintAt(screen, marginInfo,
int(bounds.X()), int(bounds.Y()+bounds.Height()+20))
ebitenutil.DebugPrintAt(screen, paddingInfo,
int(bounds.X()), int(bounds.Y()+bounds.Height()+40))
}

```

# File: margins.go

```go
package base

import (
"fmt"
)

type Margins struct {
Left float64
Top float64
Right float64
Bottom float64
}

func NewMargins(top, right, bottom, left float64) *Margins {
return &Margins{
Top: top,
Right: right,
Bottom: bottom,
Left: left,
}
}

// GetHorizontalSpacing 返回水平方向的总间距
func (m Margins) GetHorizontalSpacing() float64 {
return m.Left + m.Right
}

// GetVerticalSpacing 返回垂直方向的总间距
func (m Margins) GetVerticalSpacing() float64 {
return m.Top + m.Bottom
}

// String 返回边距的字符串表示
func (m Margins) String() string {
return fmt.Sprintf("Margins(T:%.1f R:%.1f B:%.1f L:%.1f)",
m.Top, m.Right, m.Bottom, m.Left)
}

// Clone 克隆边距
func (m *Margins) Clone() *Margins {
if m == nil {
return nil
}
return &Margins{
Top: m.Top,
Right: m.Right,
Bottom: m.Bottom,
Left: m.Left,
}
}

```

思考

评估和优化

我正在审查一个植物大战僵尸游戏的UI子模块,使用golang Ebiten引擎进行设计。重点是合理性、潜在问题和优化建议。

梳理结构

我正在分析代码文件,看到文件涉及 UI 框架、组件、容器、事件处理和布局等方面,代码量大,不宜逐行阅读。

探讨组件结构

探讨了各种组件类型、接口、事件系统和布局类,关注线程安全、事件处理和潜在内存泄漏。

审视组件功能

我正在检查BaseComponent和BaseContainer类的字段和方法,确保事件处理、锁定和事件系统的并发控制无误,避免死锁和无限循环问题。

解锁复杂

component.goHandleEvent方法中,广泛使用锁定和递归调用,存在死锁或锁定开销过大的潜在问题。

发现问题的细节

代码可能会出错,使用sync.Map不够高效。事件处理和组件复用还需优化。

探讨锁机制

我在研究使用监听器互斥来保护事件监听器的访问,这引发了对锁定状态和事件处理顺序的思考。므

优化系统结构

我在思考简化事件处理系统,使用锁定和并发机制避免死锁,避免过度使用sync.Map,考虑重置组件状态,改善代码可读性,确保继承方法正确调用,使用代码生成或反射减少事件处理模板代码,并确保测试覆盖边缘情况和并发问题。

改进方法

我正在探讨如何优化事件处理代码,确保事件阶段的正确管理和分发。我还考虑使用锁时的一致性问题。

审查代码细节

详细检查每个方法的锁定行为,确保并发测试覆盖所有情况,强化组件生命周期管理,添加Reset方法,提升整体代码风格。

这段代码试图实现一个UI框架,但存在并发问题、事件处理复杂性、内存泄漏风险、接口指针使用不当、错误处理不足和死锁风险。

回答

该代码实现了一个基于 Ebiten 引擎的植物大战僵尸游戏的 UI 模块,包含了组件、容器、布局、事件系统等多个部分。总体而言,代码结构清晰,功能划分明确,测试覆盖面较广。但是,代码中存在一些潜在的问题和需要优化的地方,主要集中在以下几个方面:

  1. 并发和锁机制

    • 不必要的复杂锁使用:代码中广泛使用了 sync.RWMutex,并通过匿名函数来限制锁的作用范围,这增加了代码的复杂性和可读性。过度使用锁也可能导致性能问题。
    • 锁的使用不一致:在一些方法中,例如 IsEnabledIsVisible,使用了读锁,但在其他地方直接访问字段,没有加锁。这可能导致数据竞争和不一致性。
    • 可能的死锁风险:在事件处理和组件树操作中,锁的层级和顺序可能导致死锁,特别是在递归调用的情况下。

    优化建议

    • 简化锁的使用:尽量减少锁的粒度和数量,避免在同一个方法中多次加锁和解锁。
    • 统一锁的策略:确保对共享数据的访问都遵循同样的锁机制,避免数据竞争。
    • 使用更高层次的并发原语:考虑使用通道(channels)或其他同步机制来替代复杂的锁操作,提高代码的可读性和可靠性。
  2. 事件系统的复杂性和潜在问题

    • 事件处理逻辑复杂:手动实现事件捕获、目标和冒泡阶段的逻辑,增加了代码的复杂性和出错的可能性。
    • 事件递归处理的问题:在 HandleEvent 方法中,通过 eventProcessing 来跟踪事件处理,防止递归,但这可能不是最有效的方式,且 fmt.Sprintf 的使用可能带来性能问题。
    • 事件监听器的管理:事件监听器的添加和移除可能存在竞争条件,尤其是在并发环境下。

    优化建议

    • 使用成熟的事件库:考虑使用已有的事件处理库,或者简化事件系统,避免手动处理复杂的事件阶段和传播逻辑。
    • 优化事件处理逻辑:减少不必要的事件属性检查和阶段切换,确保事件在组件树中的传播是清晰和可控的。
    • 改进事件监听器的管理:使用线程安全的数据结构,确保在添加和移除监听器时不会发生数据竞争。
  3. 组件池的实现问题

    • 组件重置不完全:在将组件放回池中时,仅手动重置了一些字段,如果将来添加新的字段,可能会遗漏,导致状态泄漏。
    • 类型断言和强制转换:在重置组件状态时,使用了类型断言,这可能导致代码的脆弱性和潜在的运行时错误。

    优化建议

    • 实现 Reset 方法:在组件接口中添加 Reset 方法,由各个组件自行实现状态重置,确保所有字段都被正确重置。
    • 避免类型断言:使用接口的方法而非类型断言,增强代码的健壮性和可维护性。
  4. 代码风格和 Go 语言惯用法

    • 指针的过度使用:代码中大量使用了指向接口的指针(例如 *BaseBounds),在 Go 语言中,接口本身就是一种引用类型,一般不需要使用指针。
    • 匿名函数的滥用:为了限制锁的作用域,代码中使用了大量的匿名函数,这降低了代码的可读性。
    • 错误处理缺失:部分方法中缺少对错误的处理,或者简单地返回 nil,这可能导致潜在的问题。

    优化建议

    • 遵循 Go 语言惯用法:避免使用指向接口的指针,直接使用接口类型。简化代码结构,提升可读性。
    • 减少匿名函数的使用:在需要控制锁的作用域时,可以通过重构代码逻辑,减少对匿名函数的依赖。
    • 完善错误处理:在方法中添加必要的错误检查和处理,避免将错误情况默默忽略。
  5. 性能和资源管理

    • 事件系统的性能问题:频繁的字符串格式化(例如使用 fmt.Sprintf)和 sync.Map 的使用,可能导致性能下降。
    • 内存泄漏的风险:事件监听器的添加和移除如果管理不善,可能导致内存泄漏,特别是在组件频繁创建和销毁的情况下。

    优化建议

    • 优化关键路径的性能:避免在高频率调用的代码中使用性能较低的操作,例如字符串格式化。可以使用更高效的方式生成唯一键。
    • 加强资源管理:确保在组件销毁时,所有的事件监听器和资源都被正确释放,防止内存泄漏。
  6. 测试覆盖和可靠性

    • 测试用例不充分:虽然有一些测试,但可能没有覆盖到所有的边界情况和并发场景。
    • 缺少对错误场景的测试:需要增加对异常情况的测试,确保代码在各种情况下都能正常运行。

    优化建议

    • 增加测试覆盖率:编写更多的测试用例,覆盖不同的组件组合、事件流和并发操作。
    • 模拟并发场景:使用工具或框架来模拟高并发环境下的操作,检测可能的竞争条件和死锁。

综上所述,该代码在实现上有一定的合理性,但在并发处理、事件系统、资源管理和代码风格等方面存在一些需要改进的地方。通过优化锁的使用、简化事件系统、遵循 Go 语言惯用法、加强资源管理和完善测试,可以提升代码的质量和性能。

このQ&Aを共有