Object-Oriented Design – The Role of OOP in the Business Layer

object-orientedobject-oriented-design

Below, I define an IInstantNotification Interface. TextNotification Class and EmailNotification Class inherit from this interface.

public interface IInstantNotification<T> {
        List<string> Addresses { get; set; }
        string NotificationContent { get; set; }
        T NotificationArguments { get; set; }
        bool SendNotification();
}

public class TextNotification : IInstantNotification<TextArguments>
{
        public List<string> Addresses { get; set; }
        public string NotificationContent { get; set; }
        public TextArguments NotificationArguments { get; set; }
        public bool SendNotification(){
            //send the message and confirm
            return true;
        }

        public TextNotification(
            List<string> p_Addresses,
            string p_NotificationContent,
            MailArguments p_NotificationArguments)
        {
            Addresses = p_Addresses;
            NotificationContent = p_NotificationContent;
            NotificationArguments = p_NotificationArguments;
        }
}


public class EmailNotification : IInstantNotification<MailArguments>
{
    ...
}

I can then instantiate a class, pass the args, and send the message. Pretty straight forward.

TextNotification TextObj = new TextNotification(myAddresses,myNotifContent, myArgs);
bool success = TextObj.SendNotification();

Instead, I always end up doing something like the following: scrapping the interfaces and putting everything in a static class for organization purposes only.

public static class TextNotification
{
        public static bool SendNotification(
            List<string> p_Addresses,
            string p_NotificationContent,
            MailArguments p_NotificationArguments)
        {
           //send the message and confirm
            return true;
        }   
}


public static class EmailNotification
{
    ...
}

It seems like the steps to take the action of sending a notification now have a lot less overhead (and are just as easy to understand).

bool success = TextNotification.SendNotification(myAddresses, myNotifContent, myArgs);

To my ignorant more functional programming oriented mindset, the latter is pretty simple and it seems like the best way to implement things. I have really been struggling wrapping my mind around the reason for doing it the more "OOP" way (like at the top of my post). I realize this might be too trivial of an example, but it is the best one I could come up with.

This is all coming from a middle-tier application code perspective. Oftentimes, my code intercepts an http request, invokes static functions to execute business-layer actions, and those actions call my data layer (which are just a bunch of static functions) that then call stored procedures and things bubble back up until the response is eventually returned to the client.

Representing business-layer actions with fancy OO design patterns seems pointless.

I humbly ask for someone to help me understand where my thinking is flawed. I really want to embrace the world of OOP and its fancy design patterns, as well as being able to fully leverage C# and its potential as an OOP language. I feel like I am doing a disservice to myself writing functional-first C# code…

Best Answer

"I realize this might be too trivial of an example"

That is the point. Programs start usually simple and small, but become more and more complex over time. Without introducing more structure during this process, one will easily produce a big ball of unmaintainable mud. OOP provides tools for solving this problem - giving programs more structure.

Said that, there is no need to jump from "no structure" to "fullblown OOP" in one step when a system grows - it is not even desirable. There is a middle-ground, like using classes as simple DTOs or for introducing new datatypes, then converting certain operations on those data types into member functions of those classes. There is also no need to introduce classes, objects and interfaces everywhere, when only a certain area of a program goes beyond a certain complexity.

In your example above, you may consider to introduce a non-static class TextNotification when the program becomes larger. A reason for this could be that you notice many functions where you always pass the same three-fold combination of adresses, content and arguments around. If there is currently no need for using interfaces or member functions, why overcomplicate things by introducing them (yet)?

Later, you may consider to introduce member functions into the class which operate on or with the data. SendNotification may be such a candidate (though it is debatable if a notification should know how to "send itself", or if some other component in your system should be responsible for sending notifications).

Representing business-layer actions with fancy OO design patterns seems pointless.

Introducing OO design patterns without needs is pointless for any program or module, not just for business-layer actions. Use patterns when they make your program more evolvable and maintainable, not just because they seem to be popular. And "fancy" code is never a good idea, neither in a procedural program nor in an OO program.

Related Topic