Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

In the previous article, we shared about bufferevent | Embedded Network Communication Buffer Layer, where bufferevent utilizes the Strategy Pattern design, implementing polymorphic behavior through <span>struct bufferevent_ops</span>:

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

Different types of bufferevent (such as socket, filter, SSL) share the same set of interfaces, calling their respective implementation functions through the <span>be_ops</span> pointer.

This article will share content related to the Strategy Pattern:

Strategy Pattern

The Strategy Pattern is a type of behavioral design pattern that defines a family of algorithms, encapsulating each one as an independent object, allowing them to be interchangeable. This pattern allows the variation of algorithms to be independent of the clients that use them.

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

The Strategy Pattern includes the following main roles:

  1. Context: Holds a reference to a strategy object to call the strategy.
  2. Strategy Interface: Defines a common interface for all supported algorithms or behaviors.
  3. Concrete Strategies: Specific classes that implement the strategy interface, providing concrete algorithm implementations.

In embedded systems, this pattern is particularly suitable for:

  1. Communication Protocol Switching: Dynamically switching between UART/I2C/SPI
  2. Sensor Data Processing: Using different processing strategies for different sensor types (temperature/humidity/light)
  3. Power Management: Switching power consumption strategies based on power status (battery/external power)
  4. Control Algorithms: Dynamically switching between algorithms like PID control and fuzzy control

Strategy Pattern vs Non-Strategy Pattern:

Feature Strategy Pattern Non-Strategy Pattern
Algorithm Extension Adding new strategies without modifying the context Requires modification of core logic
Conditional Branching Eliminates complex switch/case statements Contains numerous conditional branching statements
Code Reuse Strategy objects can be reused in different contexts Algorithm logic is tightly coupled with usage scenarios
Runtime Flexibility Algorithms can be switched dynamically Behavior is determined at compile time
Testing Complexity Strategy objects can be tested independently Requires simulating the entire context environment

Embedded Application Cases

Sensor data processing: Using different processing strategies for different sensor types (temperature/humidity).

Code Implementation:

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

1. Context:

// Sensor Processor (Context)
typedef struct {
    SensorStrategy strategy;
    void* sensor_data;
} SensorProcessor;

2. Strategy Interface:

// Strategy Interface
typedef void (*SensorStrategy)(void* data);

3. Concrete Strategies:

// Temperature Sensor Strategy
void temperature_strategy(void* data) {
    float* temp = (float*)data;
    printf("[C] Processing temperature: %.1fC -> Calibrated: %.1fC\n", 
           *temp, *temp + 0.5f);
}

// Humidity Sensor Strategy
void humidity_strategy(void* data) {
    int* humidity = (int*)data;
    printf("[C] Processing humidity: %d%% -> Adjusted: %d%%\n", 
           *humidity, *humidity + 2);
}

Complete C Example:

#include 

// Strategy Interface
typedef void (*SensorStrategy)(void* data);

// Temperature Sensor Strategy
void temperature_strategy(void* data) {
    float* temp = (float*)data;
    printf("[C] Processing temperature: %.1fC -> Calibrated: %.1fC\n", 
           *temp, *temp + 0.5f);
}

// Humidity Sensor Strategy
void humidity_strategy(void* data) {
    int* humidity = (int*)data;
    printf("[C] Processing humidity: %d%% -> Adjusted: %d%%\n", 
           *humidity, *humidity + 2);
}

// Sensor Processor (Context)
typedef struct {
    SensorStrategy strategy;
    void* sensor_data;
} SensorProcessor;

void process_sensor(SensorProcessor* processor) {
    processor->strategy(processor->sensor_data);
}

int main(void) {
    printf("\n--- Strategy Pattern Demo ---\n");
    
    float temp_data = 25.3f;
    int humidity_data = 45;
    
    SensorProcessor temp_processor = {temperature_strategy, &temp_data};
    SensorProcessor hum_processor = {humidity_strategy, &humidity_data};
    
    process_sensor(&temp_processor);
    process_sensor(&hum_processor);
    
    return 0;
}
Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

Complete C++ Example:

#include 
#include 

// Strategy Interface
class SensorStrategy {
public:
    virtual void process() = 0;
    virtual ~SensorStrategy() = default;
};

// Temperature Sensor Strategy
class TemperatureStrategy : public SensorStrategy {
public:
    explicit TemperatureStrategy(float temp) : temp_(temp) {}
    void process() override {
        std::cout << "Processing temperature: " << temp_ << "C -> Calibrated: " << temp_ + 0.5f << "C\n";
    }
private:
    float temp_;
};

// Humidity Sensor Strategy
class HumidityStrategy : public SensorStrategy {
public:
    explicit HumidityStrategy(int humidity) : humidity_(humidity) {}
    void process() override {
        std::cout << "Processing humidity: " << humidity_ << "% -> Adjusted: " << humidity_ + 2 << "%\n";
    }
private:
    int humidity_;
};

// Sensor Processor (Context)
class SensorProcessor {
public:
    void set_strategy(std::unique_ptr strategy) {
        strategy_ = std::move(strategy);
    }
    
    void process_sensor() {
        if(strategy_) strategy_->process();
    }
private:
    std::unique_ptr strategy_;
};

int main(void) {
    std::cout << "\n--- Strategy Pattern Demo ---\n";
    
    SensorProcessor processor;
    
    processor.set_strategy(std::make_unique(25.3f));
    processor.process_sensor();
    
    processor.set_strategy(std::make_unique(45));
    processor.process_sensor();
    
    return 0;
}

Advantages and Disadvantages

Advantages:

  1. Open/Closed Principle: New strategies can be introduced without modifying the context
  2. Elimination of Conditional Branching: Replaces complex if-else/switch statements
  3. Separation of Concerns: Decouples algorithm implementation from usage logic

Disadvantages:

  1. Increased Number of Objects: Each strategy is an independent class/object
  2. Client Cognitive Load: Requires understanding the differences between various strategies
  3. Risk of Over-Design: Simple algorithms may not require the strategy pattern

Summary of Applicability in Embedded Scenarios

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

end

Previous Recommendations

Essential Reading for Embedded Linux

Recommended Learning Path for Embedded Systems

A Reader’s Clear Logic in Questioning

Successful Transition from Mechanical to Embedded Systems

A Reader’s Experience in Audio and Video Direction During Job Hunting

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

Scan to add me on WeChat

Join the Technical Discussion Group

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

Share

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

Collect

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

Like

Essential Techniques for Embedded Development: A Practical Guide to the Strategy Pattern, Say Goodbye to If-Else Hell!

Looking

Leave a Comment