“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);
}
}
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);
}
}
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);
}
}
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();
}
- 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())
}
}
}