Design Patterns and SOLID Principles for Building a Message Sending Service
This article explains how to apply classic design patterns and the six SOLID principles—Liskov Substitution, Single Responsibility, Dependency Inversion, Interface Segregation, Law of Demeter, and Open‑Closed—to design a maintainable, extensible message‑sending system with task scheduling and dynamic provider configuration.
Before any code is written, a solid design is essential for reducing maintenance cost and ensuring stable execution throughout a project's lifecycle. The article begins with a brief introduction to design patterns, dividing them into Creational (5), Structural (7), and Behavioral (11) categories, and notes that the most commonly used patterns in projects are Factory, Abstract Factory, and Singleton.
The core requirement described is a message system that can send SMS, MMS, email, and internal messages, with dynamic addition of providers and configurable routing. The solution is built around six fundamental design principles.
1. Liskov Substitution Principle (LSP)
LSP states that objects of a subclass should be replaceable for objects of the superclass without affecting correctness. The article illustrates this with a diagram of SMS and MMS receivers that both inherit from a common Receiver class, eliminating redundant fields such as mobile.
Code example:
interface Receiver {</code>
<code> public function getRecv();</code>
<code>}</code>
<code>class SmsReceiver implements Receiver {</code>
<code> public function getRecv() {</code>
<code> return $mobile;</code>
<code> }</code>
<code>}</code>
<code>class EmailReceiver implements Receiver {</code>
<code> public function getRecv() {</code>
<code> return $email;</code>
<code> }</code>
<code>}Adding a new message type only requires creating a new class that implements Receiver, preserving LSP.
2. Single Responsibility Principle (SRP)
Each class should have only one reason to change. The article separates the sending logic ( Sender) from the request‑handling logic ( Request), preventing a monolithic class that mixes business and infrastructure concerns.
3. Dependency Inversion Principle (DIP)
High‑level modules should depend on abstractions, not concrete implementations. The Receiver interface is used by the service, allowing different concrete receivers to be injected without changing the high‑level code.
4. Interface Segregation Principle (ISP)
Clients should not be forced to depend on methods they do not use. Two small interfaces are defined: ContentWithTemplate for templated messages and Content for plain content, keeping implementations lightweight.
interface ContentWithTemplate {</code>
<code> public function getTemplate1();</code>
<code> public function getTemplate2();</code>
<code>}</code>
<code>interface Content {</code>
<code> public function getContent();</code>
<code>}5. Law of Demeter (LoD)
The design encourages weak coupling between classes, limiting each class to only the objects it directly knows, which simplifies maintenance and testing.
6. Open‑Closed Principle (OCP)
The system is extensible without modifying existing code: new receivers or providers are added by subclassing or implementing interfaces, leaving the original classes untouched.
Task Scheduling Layer
To handle message chains and load balancing, a lightweight task‑scheduling model is introduced. A Mission class represents a unit of work, while MissionExec executes it, reading tasks from Kafka and applying the same SOLID principles to the scheduling code.
class Mission {</code>
<code> public function create() {</code>
<code> // Todo: push task to Kafka</code>
<code> }</code>
<code>}</code>
<code>class MissionExec {</code>
<code> public function exec() {</code>
<code> $this->before();</code>
<code> // Todo: execute task with monitoring and retry</code>
<code> $this->do();</code>
<code> $this->after();</code>
<code> }</code>
<code>}This scheduling layer further decouples the message service from execution details, enabling horizontal scaling, load balancing, and easy addition of new task types.
In conclusion, adhering to the six design principles throughout both the message‑sending core and the task‑scheduling layer results in a clear, low‑coupling architecture that is easy to extend, maintain, and scale.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Xueersi Online School Tech Team
The Xueersi Online School Tech Team, dedicated to innovating and promoting internet education technology.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
