Skip to content

Instantly share code, notes, and snippets.

@okellodaniel
Forked from NguyenThienLy/S-O-L-I-D.md
Created May 12, 2021 19:35
Show Gist options
  • Save okellodaniel/a0ed51e252c5284f9ab196896516f1c0 to your computer and use it in GitHub Desktop.
Save okellodaniel/a0ed51e252c5284f9ab196896516f1c0 to your computer and use it in GitHub Desktop.

S — Single responsibility principle

“Do one thing and do it well”

class or module should have one, and only one, reason to be changed.

Incorrect

class User
{
    void CreatePost(Database db, string postMessage)
    {
        try
        {
            db.Add(postMessage);
        }
        catch (Exception ex)
        {
            db.LogError("An error occured: ", ex.ToString());
            File.WriteAllText("\LocalErrors.txt", ex.ToString());
        }
    }
}

Correct

class Post
{
    private ErrorLogger errorLogger = new ErrorLogger();

    void CreatePost(Database db, string postMessage)
    {
        try
        {
            db.Add(postMessage);
        }
        catch (Exception ex)
        {
            errorLogger.log(ex.ToString())
        }
    }
}

class ErrorLogger
{
    void log(string error)
    {
      db.LogError("An error occured: ", error);
      File.WriteAllText("\LocalErrors.txt", error);
    }
}

O — Open/closed principle

should be open for extensions, but closed for modification.

Incorrect

class Post
{
   void CreatePost(Database db, string postMessage)
   {
       if (postMessage.StartsWith("#"))
       {
           db.AddAsTag(postMessage);
       }
       else
       {
           db.Add(postMessage);
       }
   }
}

Correct

class Post
{
   void CreatePost(Database db, string postMessage)
   {
       db.Add(postMessage);
   }
}

class TagPost : Post
{
   override void CreatePost(Database db, string postMessage)
   {
       db.AddAsTag(postMessage);
   }
}

L — Liskov substitution principle

if S is a subtype of T, then objects of type T may be replaced (or substituted) with objects of type S.

Incorrect

class Post
{
   void CreatePost(Database db, string postMessage)
   {
       db.Add(postMessage);
   }
}

class TagPost : Post
{
   override void CreatePost(Database db, string postMessage)
   {
       db.AddAsTag(postMessage);
   }
}

class MentionPost : Post
{
   void CreateMentionPost(Database db, string postMessage)
   {
       string user = postMessage.parseUser();

       db.NotifyUser(user);
       db.OverrideExistingMention(user, postMessage);
       base.CreatePost(db, postMessage);
   }
}

class PostHandler
{
   private database = new Database();

   void HandleNewPosts() {
       List<string> newPosts = database.getUnhandledPostsMessages();

       foreach (string postMessage in newPosts)
       {
           Post post;

           if (postMessage.StartsWith("#"))
           {
               post = new TagPost();
           }
           else if (postMessage.StartsWith("@"))
           {
               post = new MentionPost();
           }
           else {
               post = new Post();
           }

           post.CreatePost(database, postMessage);
       }
   }
}

Correct

...

class MentionPost : Post
{
   override void CreatePost(Database db, string postMessage)
   {
       string user = postMessage.parseUser();

       NotifyUser(user);
       OverrideExistingMention(user, postMessage)
       base.CreatePost(db, postMessage);
   }

   private void NotifyUser(string user)
   {
       db.NotifyUser(user);
   }

   private void OverrideExistingMention(string user, string postMessage)
   {
       db.OverrideExistingMention(_user, postMessage);
   }
}

I — Interface segregation principle

Do not add additional functionality to an existing interface by adding new methods.

Instead, create a new interface and let your class implement multiple interfaces if needed.

Incorrect

interface IPost
{
   void CreatePost();
}

interface IPostNew
{
   void CreatePost();
   void ReadPost();
}

Correct

interface IPostCreate
{
   void CreatePost();
}

interface IPostRead
{
   void ReadPost();
}

D - Dependency inversion principle

  • High-level modules should not depend on low-level modules. Both should depend on abstractions.
  • Abstractions should not depend on details. Details should depend on abstractions.

we need to use a design pattern known as a dependency inversion pattern, most often solved by using dependency injection.

Incorrect

class Post
{
   private Logger _logger;

   public Post(Logger injectedLogger)
   {
       _logger = injectedLogger;
   }

   void CreatePost(Database db, string postMessage)
   {
       try
       {
           db.Add(postMessage);
       }
       catch (Exception ex)
       {
           logger.log(ex.ToString())
       }
   }
}

Correct

class Post
{
    private Logger _logger;

    public Post(Logger injectedLogger)
    {
        _logger = injectedLogger;
    }

    void CreatePost(Database db, string postMessage)
    {
        try
        {
            db.Add(postMessage);
        }
        catch (Exception ex)
        {
            logger.log(ex.ToString())
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment