DEV Community

Naomi Dennis
Naomi Dennis

Posted on

5

Single Responsibility Principle

The first concept in SOLID principles is the single responsibility principle. According to Robert Martin's Agile Software Development: Principles, Patterns and Practices, it is defined as:

A class should have only one reason to change

The definition is simple enough, but let's look at an example to really solidify its meaning.

class Game{
public void start(){
while(!winnerFound){
renderBoard();
playerTurn();
winnerFound = detectWinner();
}
}
public void playerTurn(){}
public void renderBoard(){}
public void detectWinner(){}
}

Despite the class looking relatively simple, there is actually a lot going on. Game controls how the board is rendered, how the player's turn is carried out, if a winner is found and the main game loop. If the way the board is rendered changes, #renderBoard() will have to change. If the rules of the game changes how a player should conduct their turn, #playerTurn() and possibly #detectWinner() will have to change. If we decided to create a more complicated game, where an Ai or some other high level action has to happen, #start() would have to change.

The easiest way to separate responsibility is to separate the functions into classes depending how on they change in respect to one another. #renderBoard() can be separated into its own class, because changing how the board is rendered doesn't necessitate changing the game's loop or the game's rules. It only cares about the medium the board is rendered on; for example, a phone app or command line. #playerTurn() and #detectWinner() can be separated from Game, but kept together. The rules of the game dictates how the player conducts their turn and how a player wins. If the rules of the game changes, both #detectWinner() and #playerTurn() changes.

interface Board{
public void render();
}
interface GameLogic{
public void startPlayerTurn();
public boolean winnerFound();
}
class GameCoordinator{
public void start(GameLogic chess, Board checkeredBoard){
while(!chess.winnerFound()){
checkeredBoard.render();
chess.startPlayerTurn();
}
}
}

With these changes, the only behavior left in Game is the main game loop.

In Conclusion

When determining how to separate responsibility, look for what Robert Martin calls, "an axis of change". For example, if #detectWinner() and #startPlayerTurn() behavior weren't related, we could segregate #detectWinner() into its own class. However, for our example, this is unnecessary. Be sure not to introduce needless complexity.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (1)

Collapse
 
niketazad profile image
NIKET KUMAR

good to read.

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →