- Each responsibility should be a separate class, because each responsibility is an axis of change.
- A class should have one, and only one, reason to change.
- If a change to the business rules causes a class to change, then a change to the database schema, GUI, report format, or any other segment of the system should not force that class to change.
Case 1 : Violating SRP
public class WeatherDisplay
{
private int _Temperature;
private int _WindSpeed;
public WeatherDisplay(int temperature, int windSpeed)
{
_Temperature = temperature;
_WindSpeed = windSpeed;
}
public void DisplayWeather()
{
DisplayTemperature();
DisplayWindSpeed();
}
private void DisplayTemperature()
{
println("The current temperature is: " + _Temperature + " degrees celcius.");
}
private void DisplayWindSpeed()
{
println("The current wind speed is: " + _WindSpeed + " meters per second.");
}
}
As you can see there are 2 distinct responsibilities for the class WeatherDisplay (you could even say there are 3 responsibilities). You could say one is to display the temperature and the other is to display the wind speed. Now because we are talking about 2 responsibilities we can also say that there are at least 2 reasons why we would / could change this class in the future, the temperature should be displayed in Fahrenheit and the wind speed should be displayed in knots.
Case 2 : Following SRP
Below we see how we could solve this and be coding according to the Single Responsibility Principle.
WeatherDisplay
public class WeatherDisplay
{
private DisplayTemperature _DisplayTemperature;
private DisplayWindSpeed _DisplayWindSpeed;
public WeatherDisplay(int temperature, int windSpeed)
{
_DisplayTemperature = new DisplayTemperature(temperature);
_DisplayWindSpeed = new DisplayWindSpeed(windSpeed);
}
public void DisplayWeather()
{
_DisplayTemperature.Display();
_DisplayWindSpeed.Display();
}
}
}
public class DisplayTemperature
{
private int _Temperature;
public DisplayTemperature(int temperature)
{
_Temperature = temperature;
}
public void Display()
{
println("The current temperature is: " +
_Temperature + " degrees celcius.");
}
}
public class DisplayWindSpeed
{
private int _WindSpeed;
public DisplayWindSpeed(int windSpeed)
{
_WindSpeed = windSpeed;
}
public void Display()
{
println("The current wind speed is: " +
_WindSpeed + " meters per second.");
}
}
In this second example you can see that I now re-factored the class WeatherDisplay into three classes. Weather Display still exists but now it is using the class TemperatureDisplay and WindSpeedDisplay to actually display the data.
Case 3 : Better implementation
Interface: ITextDisplay
public interface ITextDisplay {DisplayTemperature
void Display(TextWriter writer);
}
public class TemperatureDisplay implements ITextDisplay
{
private int _Temperature;
public TemperatureDisplay(int temperature)
{
_Temperature = temperature;
}
public void Display(TextWriter writer)
{
writer.WriteLine("The current temperature is: " + _Temperature + " degrees celcius.");
}
}
public class WindSpeedDisplay implements ITextDisplay
{
private int _WindSpeed;
public WindSpeedDisplay(int windSpeed)
{
_WindSpeed = windSpeed;
}
public void Display(TextWriter writer)
{
writer.WriteLine("The current wind speed is: " + _WindSpeed + " meters per second.");
}
}
As you can see now instead of providing the class WeatherDisplay with a fixed number of parameters we can now provide it with an unlimited amount of ITextDisplay implementations. The class WeatherDisplay is now responsible for providing a proper TextWriter and telling each ITextDisplay implementation to display its information. The ITextDisplay implementations now only have to write its information to the provided writer, and thus also implementing the Liskov Substitution Principle.
No comments:
Post a Comment