S.O.L.I.D Principles
A software code should depict following qualities:
Maintainability
Maintenance requires more effort than any other software engineering activity
Extensibility
Extensibility is the capacity to extend or stretch the functionality of the development environment
Modularity
Modularity is designing a system that is divided into a set of functional units that can be composed into a larger application
"They are not laws. They are not perfect truths.”
Robert C. Martin (Uncle Bob)
BAD
GOOD
BAD
GOOD
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public object Export(string format, string? location = null) {
switch(format) {
case "Excel":
// excel specific rendering and saving to location here
excel.Save(location);
break;
case "JSON":
// json specific rendering
return jsonString;
break;
default:
// default behaviour here, saving it in a text file
File.WriteAllText(location.Value, $"{FirstName} {LastName}.");
}
}
}
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class PersonExporter {
public object Export(string format, string? location = null) {
switch(format) {
case "Excel":
excel.Save(location);
break;
case "JSON":
return jsonString;
break;
default:
File.WriteAllText(location.Value,
$"{person.FirstName} {person.LastName}.");
}
}
}
public class PersonExporter {
public object Export(string format, string? location = null) {
switch(format) {
case "Excel":
excel.Save(location);
break;
case "JSON":
return jsonString;
break;
default:
File.WriteAllText(location.Value, $"{FirstName} {LastName}.");
}
}
}
interface IPersonFormatter<TReturnValue> {
TReturnValue Format(Person person, string? location);
}
public class JSONPersonFormatter : IPersonFormatter<string> {
public string Format(Person person, string? location) {
// ignoring location and executing json formatting logic
return jsonString;
}
}
public class XMLPersonFormatter : IPersonFormatter<string> {
public string Format(Person person, string? location) {
// ignoring location and executing xml formatting logic
return xmlString;
}
}
public class PersonExporter {
public object Export(Person person, IPersonFormatter formatter, string? location) {
return formatter.Format(person, location);
}
}
public class XMLPersonFormatter : IPersonFormatter<string> {
public string Format(Person person, string? location) {
// ignoring location and executing xml formatting logic
return xmlString;
}
}
public class ExcelPersonFormatter : IPersonFormatter<object> {
public object Format(Person person, string? location) {
// excel specific rendering and saving to location here
excel.Save(location);
// we return null, as we don't have anything to return...
return null;
}
}
public interface IPersonFormatter {
Stream Format(Person person);
}
public class XMLPersonFormatter : IPersonFormatter {
public Stream Format(Person person) {
// ignoring location and executing xml formatting logic
// saving it to a MemoryStream when working in .NET for example
return xmlStringMemoryStream;
}
}
public class ExcelPersonFormatter : IPersonFormatter {
public Stream Format(Person person) {
// excel specific rendering and saving to location here
excel.Save(location);
// we now don't return null, but a MemoryStream
// we don't have anything to return...
return excelWorkBookMemoryStream;
}
}
public class PersonExporter {
public Stream Export(
Person person,
IPersonFormatter formatter,
string? location) {
var stream = formatter.Format(person);
if(location.HasValue) {
// Handle saving the stream to given location/file
}
// we return the stream - even if we already saved it
return stream;
}
}
By Mecho Puh
public interface IPersonRepository {
void Save(Person person);
void Save(IEnumerable<Person> people);
IEnumerable<Person> Get();
}
public class PersonReadOnlyRepository : IPersonRepository {
public void Save(Person person) {
throw NotImplementedException();
}
public void Save(IEnumerable<Person> people) {
throw NotImplementedException();
}
public IEnumerable<Person> Get() {
return database.People.ToEnumerable();
}
}
public interface IWriteablePersonRepository {
void Save(Person person);
void Save(IEnumerable<Person> people);
}
public interface IReadablePersonRepository {
IEnumerable<Person> Get();
}
public class PersonReadOnlyRepository : IReadablePersonRepository {
public IEnumerable<Person> Get() {
return database.People.ToEnumerable();
}
}
public class PersonRepository : IReadablePersonRepository {
public IEnumerable<Person> Get() {
var db = new DatabaseContext()
return db.People.ToEnumerable();
}
}
public class PersonRepository : IReadablePersonRepository, IWriteablePersonRepository {
private readonly db;
public PersonRepository(IDatabaseContext db) {
this.db = db;
}
public IEnumerable<Person> Get() {
this.db.People.ToEnumerable();
}
}
(DRY)
(YAGNI)
(KISS)