Design Patterns: Exploration of Embedded C Language Implementation – Conclusion

Introduction:This article will provide a brief review of the patterns introduced in this series and discuss the benefits and considerations of using patterns in software design. It will also cover how we can apply these patterns in our actual software development.Pattern Summary:

  1. Strategy PatternDefines a family of algorithms, encapsulates them, and makes them interchangeable, allowing the algorithm to vary independently from the clients that use it. For example, the behaviors of various ducks or changing weapons in an RPG game.
  2. Observer Pattern

Establishes a one-to-many dependency between objects so that when one object’s state changes, all its dependents are notified and updated automatically. For example, weather monitoring notifications or the relationship between models and views in MVC.3. Decorator Pattern Dynamically adds responsibilities to objects, providing new behavior through object wrapping, which is an alternative to inheritance for extending functionality. Like various coffees at Starbucks, which can be decorated with different ingredients.4. Factory Method Pattern Defines an interface for creating objects, allowing subclasses to determine the specific class to instantiate, deferring instantiation to subclasses. For example, pizza shops in different regions create different pizzas based on local demand.5. Abstract Factory Pattern Provides an interface for creating families of related or dependent objects without specifying their concrete classes. This can be used to create different families of pizzas with regional flavors.6. Singleton Pattern Ensures that a class has only one instance and provides a global access point to it. Commonly used for thread pools, caches, logging, etc.7. Command Pattern Encapsulates a request as an object, allowing for parameterization of clients with different requests, queuing of requests, or logging of requests, and also supports undo operations. For example, button operations on a power controller.8. Adapter Pattern Converts the interface of a class into another interface that clients expect, allowing incompatible classes to work together. For example, adapting a turkey to behave like a duck.9. Template Method Pattern Defines the skeleton of an algorithm in a method, deferring some steps to subclasses, allowing subclasses to redefine certain steps without changing the algorithm’s structure. For example, the steps for brewing tea and coffee at Starbucks.10. Iterator Pattern Provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation. This can be used to traverse a merged menu from two stores.11. Composite Pattern Composes objects into tree structures to represent part-whole hierarchies, allowing clients to treat individual objects and compositions uniformly, such as a lunch menu that can include a dessert menu as a submenu.12. State Pattern Encapsulates state-based behavior, switching behavior based on the internal state of an object, making it appear as if the object has changed its class. For example, a candy machine behaves differently based on its state (whether it has coins, whether it has candy, etc.).13. Proxy Pattern Provides a surrogate or placeholder for another object to control access to it. For example, remotely monitoring a candy machine through a proxy object.14. MVC Pattern Divides an application into three core components: Model, View, and Controller. The model holds data and business logic, the view is responsible for presenting data, and the controller handles user input and decides which models and views to call.Benefits of Using Design Patterns?

  1. Improves Code Reusability and MaintainabilityDesign patterns are standardized solutions to common problems, validated through extensive practice, allowing for direct reuse and reducing redundant development. Additionally, patterns adhere to object-oriented principles (such as single responsibility and open-closed principles), making code structure clear and subsequent modifications and extensions easier. For example, the decorator pattern can dynamically extend functionality without modifying the original class, reducing maintenance costs.

  2. Enhances Code Readability and Communication EfficiencyDesign patterns have standardized naming and structure (e.g., “Singleton”, “Observer”), allowing developers to quickly understand code logic through pattern names, reducing communication costs. For instance, mentioning “Factory Pattern” immediately brings to mind the design idea of “encapsulating the object creation process” for team members.

  3. Increases System Flexibility and ExtensibilityDesign patterns promote loose coupling (e.g., the strategy pattern separates algorithms from usage scenarios, the observer pattern decouples dependencies), making systems more adaptable to changing requirements. For example, in an e-commerce discount system using the strategy pattern, adding a new discount type only requires adding a new strategy class without modifying the existing settlement logic.

  4. Reduces Complexity in Problem SolvingFor complex scenarios (e.g., multi-layer dependencies between objects, state-switching logic), design patterns provide mature handling frameworks. For example, the state pattern encapsulates the state behavior of an object, avoiding extensive <span>if-else</span> statements; the composite pattern simplifies handling of part-whole relationships through tree structures.

  5. Facilitates the Implementation of Object-Oriented Design PrinciplesDesign patterns are concrete manifestations of object-oriented principles (e.g., “Dependency Inversion”, “Liskov Substitution”). The process of using patterns is also a practice of these principles, helping to cultivate good design thinking and avoid writing tightly coupled, low-cohesion code.

Considerations When Using Design Patterns?Design patterns are a “toolbox” for software design; when used appropriately, they can significantly enhance system quality, but it is essential to remember the principle that “tools serve the problem”:First understand the essence of the problem, then choose the appropriate pattern, avoiding distortion of design just to use a pattern. Additionally, teams need to accumulate understanding of patterns through practice, balancing flexibility, readability, and performance to truly realize their value.

  1. Avoid Over-Design, Do Not Use Patterns for the Sake of PatternsThe core of design patterns is to solve problems, not to show off skills. For simple scenarios (e.g., just needing to create an object), forcibly using factory patterns or singleton patterns can increase code complexity and reduce readability. Patterns should be chosen based on actual needs, adhering to the “simplicity first” principle.

  2. Understand the Applicable Scenarios of Patterns, Avoid Rigid ApplicationEach pattern has its specific applicable scenarios; misunderstanding the design intent behind them can lead to misuse. For example, while the singleton pattern ensures a unique instance, excessive use can make global state difficult to test; using the proxy pattern for unnecessary layered encapsulation can increase system redundancy.

  3. Be Aware of the Complexity and Learning Costs of PatternsSome patterns (e.g., composite pattern, interpreter pattern) have complex structures, and if team members are unfamiliar with them, it may lead to maintenance difficulties. In team collaboration, prioritize patterns with high consensus among team members, and supplement documentation to explain design intent when necessary.

  4. Avoid Performance Issues Due to Pattern MisuseSome patterns (e.g., decorator pattern, proxy pattern) achieve functionality through multiple layers of wrapping, which may introduce additional object creation or invocation overhead; while flyweight patterns save memory, managing shared state may increase logical complexity. Performance and flexibility should be weighed during design.

  5. Flexibly Adjust According to Specific Language FeaturesDesign patterns originate from object-oriented languages (e.g., Java), but different languages have their characteristics (e.g., Python’s dynamic typing, Go’s interface design), and directly applying them may not align with language conventions. For example, in Python, a singleton can be implemented using module-level variables without strictly adhering to the private constructor approach of classes.

  6. Beware of “Silver Bullet” ThinkingDesign patterns are not a universal solution; complex systems may require a combination of multiple patterns or even custom solutions. Over-reliance on patterns may stifle innovation, and adjustments should be made flexibly according to business scenarios.

How to Choose the Right Design Pattern in Software Design?

  1. First Clarify the ProblemIs it about creating objects, handling interactions, adapting interfaces, or composing structures?
  2. Match the Pattern ScenarioBased on the problem type, filter out candidate patterns (e.g., “dynamic behavior switching” → strategy pattern).
  3. Validate with Design PrinciplesEnsure the pattern meets the system’s extensibility and coupling requirements.
  4. Weigh ConstraintsConsider performance, team understanding, and complexity, eliminating patterns that “look elegant but are not applicable”.
  5. Iterate and OptimizeStart with simple implementations and adjust pattern choices based on actual pain points.

Ultimately,the “right pattern” is one that solves the current problem at the lowest cost while leaving room for future changes— it may not be the most “advanced”, but it is certainly the most fitting for the scenario.Conclusion:Thus, the series on Design Patterns: Exploration of Embedded C Language Implementation comes to an end. I hope this series of articles has been helpful or inspiring to all readers.If you would like the author to publish other series of articles, feel free to leave me a message. 🙂Code Repository:

https://github.com/MicroDevLog/DesignPatternInC

References:

[1]. “Head First Design Patterns”, China Electric Power Press.

[2]. “Software Architecture Patterns: Volume I”

Previous Articles:Design Patterns: Exploration of Embedded C Language Implementation – 0. IntroductionDesign Patterns: Exploration of Embedded C Language Implementation – 1. Strategy PatternDesign Patterns: Exploration of Embedded C Language Implementation – 2. Observer PatternDesign Patterns: Exploration of Embedded C Language Implementation – 3. Decorator PatternDesign Patterns: Exploration of Embedded C Language Implementation – 4. Simple Factory PatternDesign Patterns: Exploration of Embedded C Language Implementation – 5. Factory Method PatternDesign Patterns: Exploration of Embedded C Language Implementation – 6. Abstract Factory PatternDesign Patterns: Exploration of Embedded C Language Implementation – 7. Singleton PatternDesign Patterns: Exploration of Embedded C Language Implementation – 8. Command PatternDesign Patterns: Exploration of Embedded C Language Implementation – 9. Adapter PatternDesign Patterns: Exploration of Embedded C Language Implementation – 10. Template Method PatternDesign Patterns: Exploration of Embedded C Language Implementation – 11. Iterator PatternDesign Patterns: Exploration of Embedded C Language Implementation – 12. Composite PatternDesign Patterns: Exploration of Embedded C Language Implementation – 13. State PatternDesign Patterns: Exploration of Embedded C Language Implementation – 14. Proxy PatternDesign Patterns: Exploration of Embedded C Language Implementation – 15. MVC PatternClick the card below to follow this public account: If you like it, remember to “share” and “recommend”, or “like” or “leave a message”.

Leave a Comment