Is this an example of a single principle of responsibility?

I made the following code example to learn how to use the generics method signature.

To get the Display () method for the client and employee, I actually started replacing my IPerson interface with the abstract class Person >.

But then I stopped, remembering the podcast in which Uncle Bob told Scott Hanselm about the principle of single responsibility , in which you should have many small classes, each of which does one specific thing, that is, that the Client class should not have Print () and Save () and the CalculateSalary () method , but you must have the CustomerPrinter class and the CustomerSaver class and the CustomerSalaryCalculator class .

This seems like a weird way of programming. However, getting rid of my interface also feels bad (since many IoC containers and DI examples use them inherently), so I decided to try the principle of single responsibility.

So, the following code is different from the one I programmed in the past (I would have made an abstract class using the Display () method and got rid of the interface), but based on what I have heard about the decoupling and SOLID principles, this new way coding (interface and PersonDisplayer class) I think this is the right way .

I would like to hear if others think differently on this issue or experience positive or negative consequences of this (for example, a cumbersome number of classes, each of which does one thing, etc.).

using System; namespace TestGeneric33 { class Program { static void Main(string[] args) { Container container = new Container(); Customer customer1 = container.InstantiateType<Customer>("Jim", "Smith"); Employee employee1 = container.InstantiateType<Employee>("Joe", "Thompson"); Console.WriteLine(PersonDisplayer.SimpleDisplay(customer1)); Console.WriteLine(PersonDisplayer.SimpleDisplay(employee1)); Console.ReadLine(); } } public class Container { public T InstantiateType<T>(string firstName, string lastName) where T : IPerson, new() { T obj = new T(); obj.FirstName = firstName; obj.LastName = lastName; return obj; } } public interface IPerson { string FirstName { get; set; } string LastName { get; set; } } public class PersonDisplayer { private IPerson _person; public PersonDisplayer(IPerson person) { _person = person; } public string SimpleDisplay() { return String.Format("{1}, {0}", _person.FirstName, _person.LastName); } public static string SimpleDisplay(IPerson person) { PersonDisplayer personDisplayer = new PersonDisplayer(person); return personDisplayer.SimpleDisplay(); } } public class Customer : IPerson { public string FirstName { get; set; } public string LastName { get; set; } public string Company { get; set; } } public class Employee : IPerson { public string FirstName { get; set; } public string LastName { get; set; } public int EmployeeNumber { get; set; } } } 
+6
c # design-patterns solid-principles
Mar 18 '09 at 17:11
source share
5 answers

I like to think of the principle of single responsibility as the implementation of the separation of duties . Before I begin to split my classes as I see fit, I try to think about what each class should be responsible for.

Your classes are pretty simple and well suited for an abstract class with Print() and Save() functions implemented, as you mentioned. I would like to keep this design over your current one.

However, if printing and saving were more complex tasks that could be performed differently, then the highlighted Printer or Saver class would be highlighted, since this responsibility is now more complex. The "complexity" of the threshold for creating a new class is very subjective and will depend on the specific situation, but, in the end, the code is just an abstraction for us, people with a low level of understanding, so make it so that it is the most intuitive.

The Container class is a bit misleading. In fact, it "contains nothing." It actually implements a Factory method template and will win on behalf of the factory.

In addition, your PersonDisplayer never created and cannot provide all of its functions using static methods, so why not make it a static class? It is not uncommon for utility classes such as Printers or contributors to be static. If you do not need to have separate printer instances with different properties, save it in a static form.

+8
Mar 18 '09 at 17:39
source share

I think you're on the right track. Although I'm not quite sure about the container class. I usually stuck with a simpler solution to just use the “new” for these objects, unless you need a business interface for this interface. (I do not consider a "tidy" business requirement in this sense)

But the separation of responsibility "for the customer" from "displaying the customer" is nice. Stick to this, this is a good interpretation of SOLID principles.

Personally, I have now completely stopped using any static methods in this kind of code, and I rely on DI to get all the right service objects in the right place and time. Once you start developing your SOLID principles, you will find that you are doing a lot more work. Try working on these naming conventions to stay consistent.

+4
Mar 18 '09 at 17:28
source share

Well, I’ve never heard of this “principle of shared responsibility”, but it seems to me that what you do with these CustomerPrinter and CustomerSaver classes simply turns the classes back into structures and object-oriented everything.

For example, this would mean that different types of customers would need, in different cases, the CustomerPrinter class if they had to be printed differently. But, as I understand it, one of the points of OO organization, as well as the use of inheritance trees and all that, is to get rid of the need for this CustomerPrinter to know how to print everything: customers know how to print themselves.

I do not believe in strict adherence to these paradigms. For example, I'm not sure what the difference is between an interface and an abstract class in your case. But then again, I'm a C ++ programmer, not a C # programmer ...

+1
Mar 18 '09 at 17:22
source share

A few notes:

  • In general, SRP is good, as is separation of display formatting from data.
  • Given the display, etc., I would prefer to think in terms of services, that is, PersonDisplayer is single, stand-alone and offers the function of displaying strings (IPerson). IMHO, a special class wrapper to provide display does not offer any benefits.
  • However, if you used data binding for wpf, you might have a DisplayablePerson class that will distribute PropertyChanged if Person is changed. You put DisplayablePerson objects in an ObservableCollection and serve it as the ItemsSource of some list control.
  • Why do we need a container, is it only for creating an instance and setting up an instance? Try customer Customer1 = new customer {FirstName = "Jim", LastName = "Smith"};

  • On a side note, I tried the object object.Method <SomeType> (...) several times, as this seemed like the fastest and easiest solution. However, after some time, I always ran into problems with this and ended up creating an object. Method (Type someTypeType, ...)

+1
Mar 18 '09 at 17:44
source share

You can take a look at IFormattable and IFormatProvider .

The structure has formatting classes for support.

0
Mar 18 '09 at 18:15
source share



All Articles