Skip to main content
Version: Latest

ActionResult Architecture

Overview

ActionResult serves as the universal return type for all actions in the Brobot framework, encapsulating comprehensive information generated during action execution. Version 2.0 introduces a component-based architecture that transforms the original 1113-line monolithic class into a well-structured system of focused, single-responsibility components.

Architecture Evolution

Legacy Architecture (v1.x)

The original ActionResult was a monolithic class handling 30+ responsibilities:

  • Match collection management
  • Text extraction and aggregation
  • Timing and duration tracking
  • Scene analysis data
  • Region definitions
  • Movement tracking
  • Execution history
  • State management
  • Logging and metrics
  • Sorting and filtering operations
  • Statistical calculations
  • Serialization concerns

Component-Based Architecture (v2.0)

The refactored architecture delegates responsibilities to specialized components while maintaining complete backward compatibility through a facade pattern.

┌─────────────────────────────────────────────────────────────────┐
│ ActionResult │
│ (Facade) │
├─────────────────────────────────────────────────────────────────┤
│ Core Fields: │
│ - actionDescription: String │
│ - success: boolean │
│ - actionConfig: ActionConfig │
│ - outputText: String │
├─────────────────────────────────────────────────────────────────┤
│ Component Delegates: │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ MatchCollection │ │ TimingData │ │
│ │ - matches │ │ - startTime │ │
│ │ - sorting │ │ - endTime │ │
│ │ - filtering │ │ - duration │ │
│ └──────────────────┘ └──────────────────┘ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │TextExtractionResult│ │ StateTracker │ │
│ │ - accumulated │ │ - activeStates │ │
│ │ - selected │ │ - stateMatches │ │
│ │ - matchText │ │ - activations │ │
│ └──────────────────┘ └──────────────────┘ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ RegionManager │ │ MovementTracker │ │
│ │ - definedRegions │ │ - movements │ │
│ │ - namedRegions │ │ - distances │ │
│ │ - unions │ │ - paths │ │
│ └──────────────────┘ └──────────────────┘ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ ActionAnalysis │ │ExecutionHistory │ │
│ │ - sceneAnalyses │ │ - records │ │
│ │ - masks │ │ - lifecycle │ │
│ │ - customAnalysis │ │ - timeline │ │
│ └──────────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Core Components

1. MatchCollection

Responsibility: Manages all match-related operations

public class MatchCollection {
private List<Match> matches;
private List<Match> initialMatches;
private int maxMatches;

// Key operations
public void add(Match... matches);
public void sort(SortStrategy strategy);
public Optional<Match> getBest();
public MatchCollection filter(Predicate<Match> predicate);
public MatchStatistics getStatistics();
}

Features:

  • Multiple sorting strategies (score, size, distance)
  • Flexible filtering with predicates
  • Statistical analysis delegation
  • Set operations (minus, intersection)
  • Automatic max match enforcement

2. TimingData

Responsibility: Handles all timing and duration tracking

public class TimingData {
private LocalDateTime startTime;
private LocalDateTime endTime;
private Duration totalDuration;
private List<TimeSegment> segments;

// Key operations
public void start();
public void stop();
public Duration getElapsed();
public void addSegment(String name, Duration duration);
}

Features:

  • Automatic timing calculation
  • Phase timing support
  • Overhead calculation
  • Human-readable formatting

3. TextExtractionResult

Responsibility: Manages text extraction and OCR results

public class TextExtractionResult {
private Text accumulatedText;
private String selectedText;
private Map<Match, String> matchTextMap;

// Key operations
public void addText(String text);
public void addMatchText(Match match, String text);
public String getCombinedText();
}

Features:

  • Accumulated text tracking
  • Match-specific text mapping
  • Selected text management
  • Multiple text source merging

4. StateTracker

Responsibility: Tracks state information during execution

public class StateTracker {
private Set<String> activeStates;
private Map<String, List<Match>> stateMatches;
private Map<String, Integer> stateActivationCounts;

// Key operations
public void recordActiveState(String stateName);
public void recordStateMatch(String stateName, Match match);
public Optional<String> getMostActiveState();
}

Features:

  • Active state detection
  • State-match associations
  • Activation frequency tracking
  • State activity analysis

5. RegionManager

Responsibility: Manages region definitions and operations

public class RegionManager {
private List<Region> definedRegions;
private Map<String, Region> namedRegions;

// Key operations
public void defineRegion(Region region);
public void defineNamedRegion(String name, Region region);
public Optional<Region> getUnion();
public Optional<Region> getIntersection();
}

Features:

  • Anonymous and named regions
  • Union/intersection calculations
  • Area-based sorting
  • Primary region access

6. MovementTracker

Responsibility: Tracks drag and movement operations

public class MovementTracker {
private List<Movement> movements;

// Key operations
public void recordMovement(Movement movement);
public double getTotalDistance();
public boolean isClosedPath(double tolerance);
public Optional<Region> getBoundingBox();
}

Features:

  • Movement sequence tracking
  • Distance calculations
  • Path analysis (closed/open)
  • Bounding box computation

7. ActionAnalysis

Responsibility: Manages analysis data and results

public class ActionAnalysis {
private SceneAnalyses sceneAnalyses;
private Mat mask;
private Map<String, Object> customAnalysis;

// Key operations
public void addSceneAnalysis(SceneAnalysis analysis);
public void addCustomAnalysis(String key, Object data);
public <T> Optional<T> getCustomAnalysis(String key, Class<T> type);
}

Features:

  • Scene analysis aggregation
  • Binary mask management
  • Custom analysis storage
  • Type-safe retrieval

8. ExecutionHistory

Responsibility: Tracks action execution history

public class ExecutionHistory {
private List<ActionRecord> records;
private ActionLifecycle lifecycle;

// Key operations
public void recordStep(ActionRecord record);
public List<ActionRecord> getSuccessfulSteps();
public double getSuccessRate();
public String formatTimeline();
}

Features:

  • Step-by-step recording
  • Success/failure analysis
  • Timeline visualization
  • Duration tracking

Support Components

MatchStatistics

Provides statistical analysis of match collections:

  • Median region/location calculation
  • Score distribution analysis
  • Confidence level determination
  • Density calculations
  • Bounding box computation

MatchFilter

Static utility for filtering operations:

  • Filter by state object/owner
  • Score-based filtering
  • Area-based filtering
  • Distance-based filtering
  • Duplicate removal

ActionResultBuilder

Fluent builder for constructing ActionResult instances:

ActionResult result = new ActionResultBuilder()
.withSuccess(true)
.withDescription("Found button")
.withMatches(matchList)
.withTiming(startTime, endTime)
.withActiveState("MainMenu")
.build();

Design Patterns

1. Facade Pattern

ActionResult acts as a facade, providing a simplified interface to the complex subsystem of components while maintaining backward compatibility.

2. Delegation Pattern

All operations are delegated to specialized components, keeping ActionResult focused on coordination rather than implementation.

3. Builder Pattern

ActionResultBuilder provides flexible construction with optional parameters and method chaining.

4. Strategy Pattern

MatchCollection uses strategy pattern for sorting operations with configurable strategies.

5. Repository Pattern

Components like RegionManager and StateTracker act as repositories for their respective domain objects.

Integration Points

With Action Classes

public class Click {
public ActionResult execute(ObjectCollection objects) {
ActionResult result = new ActionResult(clickOptions);
// Populate result using components
result.add(foundMatch);
result.setSuccess(true);
return result;
}
}

With Logging System

// Components provide formatted output
String matchSummary = result.getMatchCollection().getStatistics().format();
String timingSummary = result.getTimingData().format();
String stateSummary = result.getStateTracker().format();

With Testing Framework

// Fine-grained assertions on components
assertThat(result.getMatchCollection().size()).isEqualTo(3);
assertThat(result.getTimingData().getExecutionTimeMs()).isLessThan(1000);
assertThat(result.getStateTracker().isStateActive("LoginScreen")).isTrue();

Performance Characteristics

Memory Efficiency

  • Lazy Initialization: Components created on demand
  • Shared References: No unnecessary copying
  • Bounded Collections: MaxMatches enforcement

Computational Efficiency

  • O(1) Access: Direct component access
  • O(n log n) Sorting: Efficient match sorting
  • O(n) Filtering: Linear filtering operations
  • Cached Statistics: Statistics calculated once

Garbage Collection

  • Reduced Object Graph: Smaller, focused objects
  • Clear Ownership: Components own their data
  • Explicit Cleanup: Clear() methods on components

Extension Points

Custom Analysis Types

// Add custom analysis data
result.getActionAnalysis().addCustomAnalysis("colorProfile", colorData);

// Retrieve with type safety
Optional<ColorProfile> profile = result.getActionAnalysis()
.getCustomAnalysis("colorProfile", ColorProfile.class);

Custom Sorting Strategies

// Extend MatchCollection.SortStrategy
matchCollection.sort(SortStrategy.CUSTOM_RELEVANCE);

Custom Statistics

// Extend MatchStatistics for domain-specific metrics
public class GameMatchStatistics extends MatchStatistics {
public double getAverageHealthBarFullness() { ... }
}

Migration Guide

For API Consumers

No changes required! The facade maintains complete backward compatibility:

// Old code continues to work
ActionResult result = action.execute();
result.add(match);
result.sortMatchObjects();
List<Match> matches = result.getMatchList();

For Action Implementers

Use the builder for cleaner construction:

// Old way
ActionResult result = new ActionResult();
result.setSuccess(true);
result.add(matches);
result.setDuration(duration);

// New way (optional)
ActionResult result = ActionResultBuilder.successWith(matches)
.withTiming(startTime, endTime)
.build();

For Framework Extenders

Access components directly for advanced operations:

// Direct component access
MatchCollection matches = result.getMatchCollection();
MatchStatistics stats = matches.getStatistics();
double confidence = stats.getConfidence();

Testing Strategy

Component Unit Testing

Each component has focused unit tests:

@Test
void testMatchCollectionSorting() {
MatchCollection collection = new MatchCollection();
collection.add(match1, match2, match3);
collection.sortByScoreDescending();

assertThat(collection.getBest()).contains(match3);
}

Integration Testing

Test component interactions:

@Test
void testActionResultDelegation() {
ActionResult result = new ActionResult();
result.add(match);

// Verify delegation
assertThat(result.getMatchCollection().contains(match)).isTrue();
assertThat(result.getStateTracker().getActiveStates()).contains(stateName);
}

Performance Testing

Verify performance characteristics:

@Benchmark
public void benchmarkMatchSorting() {
result.sortMatchObjectsDescending();
}

Security Considerations

Input Validation

  • Components validate input parameters
  • Null-safe operations throughout
  • Bounded collection sizes

Data Isolation

  • Components encapsulate their data
  • No shared mutable state
  • Defensive copying where needed

Serialization Safety

  • @JsonIgnore on non-serializable fields
  • Clean separation of transient data
  • Controlled exposure of internal state

Future Enhancements

Planned Improvements

  1. Async Support: Concurrent component operations
  2. Streaming API: Process large result sets efficiently
  3. Event System: Observable result changes
  4. Metrics Dashboard: Real-time performance visualization
  5. Plugin Architecture: Dynamic component registration

Potential Optimizations

  1. Object Pooling: Reuse component instances
  2. Lazy Loading: Defer expensive calculations
  3. Caching Layer: Cache computed statistics
  4. Compression: Compress large match collections

Best Practices

Do's

  • ✅ Use components for focused operations
  • ✅ Leverage builder for complex construction
  • ✅ Access statistics for analysis
  • ✅ Clear components when done
  • ✅ Use appropriate sorting strategies

Don'ts

  • ❌ Don't access component internals directly
  • ❌ Don't modify collections while iterating
  • ❌ Don't ignore null checks
  • ❌ Don't bypass the facade for basic operations
  • ❌ Don't store references to internal collections

Component Reference

ComponentLinesResponsibilityKey Methods
MatchCollection280Match managementadd(), sort(), filter(), getBest()
TimingData150Timing trackingstart(), stop(), getElapsed()
MatchStatistics200Statistical analysisgetMedian(), getConfidence()
TextExtractionResult120Text managementaddText(), getCombinedText()
StateTracker160State trackingrecordActiveState(), getMostActiveState()
RegionManager180Region managementdefineRegion(), getUnion()
MovementTracker140Movement trackingrecordMovement(), getTotalDistance()
ActionAnalysis140Analysis dataaddSceneAnalysis(), addCustomAnalysis()
ActionMetrics200Performance metricsrecordExecutionTime(), getEfficiencyScore()
ExecutionHistory180Execution trackingrecordStep(), getSuccessRate()
MatchFilter260Filtering utilitiesbyMinScore(), nearLocation()
ActionResultBuilder400Result constructionwithMatches(), build()

Conclusion

The refactored ActionResult architecture transforms a monolithic class into a well-structured system of focused components. This design provides:

  • Better Maintainability: Each component has a single, clear responsibility
  • Enhanced Testability: Smaller units are easier to test in isolation
  • Improved Extensibility: New features can be added to specific components
  • Backward Compatibility: Existing code continues to work unchanged
  • Performance Benefits: Lazy initialization and focused operations

The component-based architecture positions ActionResult for future growth while maintaining the stability and reliability expected by existing consumers.