This is the 28th day of my participation in the August Challenge


1. The secrets behind the publication of the article

At the beginning of 2020, I decided to quit my job. I was under a lot of pressure with a college degree, and my resume was almost no advantage. I had a premonition that my resume would be lost by then. There is no way, there is no advantage to make advantage, so I decided to use the tomb-sweeping Day three days holiday time to write a blog system out, I have their own server and domain name, I can deploy this project before the resume, and write on the resume, I believe that will add many points.

I didn’t leave my room for three days during qingming Festival. What I did every day was: write code, order take-out food and sleep. Fortunately, the writing of the project went smoothly. The whole function was completed within three days. Finally, the deployment went online and the access link was written on the resume.

In this blog project, what impressed me most was the publication of the article. When a user posts an article, the system needs to complete three main actions:

  1. Article data is saved to the database.
  2. The article content is segmented into Chinese words, and the full text index is set up and stored in ElasticSearch.
  3. Redis sets up the BitMap as a Bloom filter to prevent cache penetration.

We tried to describe this process in pseudocode: DBClient

class DBClient {

    void insert(a){
            print("Save article to database");
    }

    void update(a){
            print("Article updated to database");
    }

    void delete(a){
            print("Article deleted from database"); }}Copy the code

ElasticSearchClient

class ElasticSearchClient {

    void addDocument(a){
            print("ElasticSearch builds article index..."); }... }Copy the code

RedisClient

class RedisClient {

    void setBitMap(a){
        print("Set the bitmap..."); }}Copy the code

When the client needs to publish an article, it calls:

DBClient dbClient = new DBClient();
ElasticSearchClient elasticSearchClient = new ElasticSearchClient();
RedisClient redisClient = new RedisClient();

// Save to database
dbClient.insert();
// text index
elasticSearchClient.addDocument();
// Set the BitMap to be used as a Bloom filter
redisClient.setBitMap();
Copy the code

The functionality is fine, but what’s the problem with this implementation? The client needs to rely on DBClient, ElasticSearchClient, RedisClient classes, and needs to know all the process of publishing articles very clearly. The coupling is too high, what if there is a step in the middle later? The client will go crazy.

Now that we know what’s bad, let’s optimize.

Can Posting, modifying, and deleting articles be viewed as a command? The caller issues a command, the receiver executes it, and the caller does not care about the details of the command execution, thus achieving loose coupling.

Abstract command class

abstract class Command {
	protected DBClient dbClient = new DBClient();
	protected ElasticSearchClient elasticSearchClient = new ElasticSearchClient();
	protected RedisClient redisClient = new RedisClient();

	// Command execution, subclass implementation
	abstract void execute(a);
}
Copy the code

Executor

class Invoker {
    Command command;

    // Set the command
    void setCommand(Command command) {
            this.command = command;
    }

    // Execute the command
    void action(a){
            this.command.execute(); }}Copy the code

Post command

class PublishCommand extends Command{

    @Override
    void execute(a) {
            super.dbClient.insert();
            super.elasticSearchClient.addDocument();
            super.redisClient.setBitMap(); }}Copy the code

The client side of the call becomes very simple, the client just need to create the specified command, give Invoker to execute, as the command execution details it does not care.

What if the user wants to modify the article? It’s as simple as extending the modify command:

class UpdateCommand extends Command{

    @Override
    void execute(a) {
        // Update database
        super.dbClient.update();
        // Update the index
        super.elasticSearchClient.updateDocument();
        // Modify the article with the same ID and bitmap.}}Copy the code

All the client needs to do is create the UpdateCommand and hand it to Invoker to execute. This is command mode!

2. Define the command mode

Encapsulating a request as an object allows you to parameterize clients with different requests, queue requests or log requests, and provide command undo and recovery capabilities.

Command pattern generic class diagram

  • Receiver: The Receiver of commands and the role that does the actual work.
  • Command: Defines the operations of all commands.
  • ConcreteCommand: Actual commands, N command classes for N commands.
  • Invoker: The caller who receives the command and executes it.

The Command pattern is simple and common. It is very encapsulation, separating the Invoker of the requester from the Receiver of the executor, and it is very extensible. To add commands, you can simply subclass Command.

3. Advantages and disadvantages of command mode

advantages

  1. With coupling reduced, there is no dependency between the requester and the performer; the requester is only responsible for receiving the command and executing it, regardless of who or how it is executed.
  2. Good scalability, extending a command is very simple, derivedCommandSubclasses will do.
  3. Requests for commands can be queued and logged.

Disadvantages If there are N commands, you need to write N Command subclasses. If there are too many commands, the number of classes will swell.

4. To summarize

You can use command mode as long as you think it is a command. Command mode can also be combined with other modes, such as “memo mode” to achieve command undo function, “chain of responsibility mode” to achieve command family resolution. The command pattern decouples the caller of the command from the executor of the command. The client only cares about the command to be executed, and it does not care about who executed the command and how it was executed. This is the embodiment of high cohesion. In addition, Invoker can also do some articles while executing commands, such as queuing command execution, logging, etc.