DEV Community

RedCalmContemplator
RedCalmContemplator

Posted on

Object Oriented and Functional Programming

In our day to day programming, one must follow a certain paradigm
wether its procedural, imperative, object oriented or functional programming.

In this post we will explore object oriented and functional programming,
explore a simple example on how to implement a simple user story for both paradigms.

I'm no expert in object oriented nor design patterns in OOP, as well as
functional programming. You may find this post opinionated on implementation level.
But I will try my best to express it on how we might code it on our day to day basis.
With all the caveats, let's proceed anyway.


User story

A Customer should have the following information

  • firstname
  • middlename (not required)
  • lastname
  • age

Sales clerk should allow view of the following:

Name: {lastname}, {firstname} {middleInitial}

or

Name: {lastname}, {firstname}

Status: {Allowed} or {Not Allowed}

Notes

  • Name should have a period at the end, if has a middle name, otherwise none.
  • Status allowed if the customer is in legal age.

Object Oriented Programming

OOP encapsulate states in an object, object is created using an instance of class, classes have methods that operates the object states.


class Customer {
    firstname: string
    middlename: string
    lastname: string
    age: number
}

Enter fullscreen mode Exit fullscreen mode

Okay, so far so good.

We also want a concatenated information of the customer name,
we should achive this by creating a method that formats the
customer information.

class Customer {

...

+   formattedName: string
+   
+   formatCustomerName () {
+       this.formattedName = `${this.lastname}, ${this.firstname}`;
+       if (this.middlename) {
+           if (this.middlename[0]) {
+               this.formattedName = `${this.formattedName} ${this.middlename[0]}.`
+           }   
+       }
+       this.formattedName = 'Name: ' + this.formattedName;
+   }
}
Enter fullscreen mode Exit fullscreen mode

and finaly we add status.

class Customer {

...

+   isLegalAge () {
+       return this.age >= 18;
+   }

+   getStatus (): string {
+       return 'Status: ' + this.isLegalAge() ? 'Allowed' : 'Not Allowed'
+   }

}
Enter fullscreen mode Exit fullscreen mode

At this point, we already fulfill the requirement. We can already ship right?

Wait, What about if we have another format for customer name?

We could add another method to our Customer class, if we do that we end up many formatters in a single class, and the customer has now many responsibility at hand.

So, lets introduce a formatter in strategy pattern.


interface ICustomerFormatter {

    format(customer: Customer): string
}

class SalesClerkCustomerFormatter implements ICustomerFormatter {

    format(customer: Customer): string {
        let formattedName = `${customer.lastname}, ${customer.firstname}`;
        if (customer.middlename) {
            if (customer.middlename[0]) {
                return formattedName = `${formattedName} ${customer.middlename[0]}.`
            }
        }
        return 'Name: ' + formattedName;
    }
}

class ReportingCustomerFormatter implements ICustomerFormatter {

    format(customer: Customer): string {

        throw new Error('not implemented yet');
    }
}
Enter fullscreen mode Exit fullscreen mode

class Customer {

...

-   formatCustomerName () {
-       this.formattedName = `${this.lastname}, ${this.firstname}`;
-       if (this.middlename) {
-           if (this.middlename[0]) {
-               this.formattedName = `${this.formattedName} ${this.middlename[0]}.`
-           }   
-       }
-       this.formattedName = 'Name: ' + this.formattedName;
-   }
+   formatCustomerName (formatter: ICustomerFormatter) {
+       this.formattedName = 'Name: ' + formatter.format(this);
    }

...

}

Enter fullscreen mode Exit fullscreen mode

// Usage

let customer = new Customer();
customer.firstname = 'sansa';
customer.middlename = 'tully';
customer.lastname = 'stark';

customer.formatCustomerName(new SalesClerkCustomerFormatter());
customer.formattedName; // Sales Clerk formatted customer name;

customer.formatCustomerName(new ReportingCustomerFormatter());
customer.formattedName; // Reporting formatted customer name;

Enter fullscreen mode Exit fullscreen mode

Functional Programming

Functional programming works on data and pure functions that transforms them.

We could start by defining a record for our customer.


type Customer = {
    firstname: string
    middlename: string
    lastname: string
    age: number
}

Enter fullscreen mode Exit fullscreen mode

and we add helper functions.


const formatSalesClerkCustomerName = (customer: Customer): string => {
    const formattedName = `${customer.lastname}, ${customer.firstname}`;
    return (customer.middlename && customer.middlename[0]) ?
        `${formattedName} ${customer.middlename[0]}.` : formattedName;
};

const isCutomerLegalAge = (customer: Customer): boolean => {
    return customer.age > 18;
};

const customerStatus = (customer: Customer): string => {
    return 'Status: ' + isCutomerLegalAge(customer)? 'Allowed' : 'Not Allowed'; 
};

Enter fullscreen mode Exit fullscreen mode

That's all we need.

How about multiple formats for customer name?

We could also have a strategy pattern in FP, we have to use a higher order function for that.


const formatCustomerName = (
    customer: Customer,
    nameFormatter: (customer: Customer) => string): string => {
    return 'Name: ' + nameFormatter(customer);
};

const reportingFormatter = (customer: Customer): string => {

    throw new Error('not implemented yet');
};


let bran = {
    firstname = 'bran',
    middlename = 'tully',
    lastname = 'stark',
    age: 8
}

// Usage

formatCustomerName(bran, formatSalesClerkCustomerName);
formatCustomerName(bran, formatReporting);

Enter fullscreen mode Exit fullscreen mode

Conclusion

We saw two different paradigms and example on how its implemented,
Decomposed using Strategy Pattern. Choosing paradigm is merley up to you, or your team standard.

I for myself tends to write in both paradigm. When confronted with calculations and working on mapping asynchronous tasks, I leans towards FP. On the other hand, for example Controllers from MVC, then I use OOP and as much as possible using pure functions, on methods.


Let me know what you think below.

Source Codes:

OOP Code

FP Code

Top comments (0)