---
title: "SOLID: A refactoring example"
description: A concrete example on how to refactor a Spring Boot service so that it follows SOLID principles.
image: https://blog.ippon.tech/hubfs/Imported_Blog_Media/SOLID_Refactoring-3.png
---

[Skip to main content](https://blog.ippon.tech/refactoring-to-solid#main)

[![IpponLogoKleinBlue](https://blog.ippon.tech/hs-fs/hubfs/IpponLogoKleinBlue.png?width=219&height=64&name=IpponLogoKleinBlue.png) ![IpponLogoKleinBlue](https://blog.ippon.tech/hs-fs/hubfs/IpponLogoKleinBlue.png?width=219&height=64&name=IpponLogoKleinBlue.png) ![IpponLogoKleinBlue](https://blog.ippon.tech/hs-fs/hubfs/IpponLogoKleinBlue.png?width=168&height=49&name=IpponLogoKleinBlue.png) ![IpponLogoKleinBlue](https://blog.ippon.tech/hs-fs/hubfs/IpponLogoKleinBlue.png?width=168&height=49&name=IpponLogoKleinBlue.png)](https://ipponusa.com/)

- [Home](https://ipponusa.com)
- [Show submenu for About About](https://ipponusa.com/about-us) 
    - [Who We Are](https://ipponusa.com/who-we-are)
    - [Careers](https://ipponusa.com/careers)
    - [Show submenu for Our Partners Our Partners](https://ipponusa.com/our-partners/) 
          - [AWS](https://ipponusa.com/our-partners/aws/)
          - [Snowflake](https://ipponusa.com/our-partners/snowflake/)
          - [Databricks](https://ipponusa.com/our-partners/databricks/)
          - [Microsoft](https://ipponusa.com/our-partners/microsoft/)
- [Show submenu for Services Services](https://ipponusa.com/services) 
    - [Snowflake](https://ipponusa.com/service/snowflake-concierge/)
    - [Artificial Intelligence](https://ipponusa.com/service/artificial-intelligence/)
    - [Data & Analytics](https://ipponusa.com/service/data-analytics/)
    - [Cloud Strategy](https://ipponusa.com/service/cloud-strategy/)
    - [Platform Modernization](https://ipponusa.com/service/platform-moderization/)
    - [Product Innovation](https://ipponusa.com/service/product-innovation/)
    - [Operating Model](https://ipponusa.com/service/operating-model/)
- [Blogs](https://blog.ippon.tech/)
- [Success Stories](https://ipponusa.com/success-stories/)
- [Show submenu for Resources Resources](https://ipponusa.com/resources/) 
    - [eBooks](https://ipponusa.com/ebooks/)
    - [The Data Pour](https://info.ippon.tech/the-data-pour)
    - [Videos & Webinars](https://info.ippon.tech/videos-and-webinars)
    - [Media Center](https://ipponusa.com/media-center/)

Search

Open main navigation

Close main navigation

- [Home](https://ipponusa.com)
- Show submenu for About About 
  
    - About
    - [About](https://ipponusa.com/about-us)
    - [Who We Are](https://ipponusa.com/who-we-are)
    - [Careers](https://ipponusa.com/careers)
    - Show submenu for Our Partners Our Partners 
      
          - Our Partners
          - [Our Partners](https://ipponusa.com/our-partners/)
          - [AWS](https://ipponusa.com/our-partners/aws/)
          - [Snowflake](https://ipponusa.com/our-partners/snowflake/)
          - [Databricks](https://ipponusa.com/our-partners/databricks/)
          - [Microsoft](https://ipponusa.com/our-partners/microsoft/)
- Show submenu for Services Services 
  
    - Services
    - [Services](https://ipponusa.com/services)
    - [Snowflake](https://ipponusa.com/service/snowflake-concierge/)
    - [Artificial Intelligence](https://ipponusa.com/service/artificial-intelligence/)
    - [Data & Analytics](https://ipponusa.com/service/data-analytics/)
    - [Cloud Strategy](https://ipponusa.com/service/cloud-strategy/)
    - [Platform Modernization](https://ipponusa.com/service/platform-moderization/)
    - [Product Innovation](https://ipponusa.com/service/product-innovation/)
    - [Operating Model](https://ipponusa.com/service/operating-model/)
- [Blogs](https://blog.ippon.tech/)
- [Success Stories](https://ipponusa.com/success-stories/)
- Show submenu for Resources Resources 
  
    - Resources
    - [Resources](https://ipponusa.com/resources/)
    - [eBooks](https://ipponusa.com/ebooks/)
    - [The Data Pour](https://info.ippon.tech/the-data-pour)
    - [Videos & Webinars](https://info.ippon.tech/videos-and-webinars)
    - [Media Center](https://ipponusa.com/media-center/)
- Search
- [Contact Us](https://ipponusa.com/contact/)

[Contact Us](https://ipponusa.com/contact/)

# SOLID: A refactoring example

![Ben Scott](https://app.hubspot.com/settings/avatar/d41d8cd98f00b204e9800998ecf8427e)

 by [Ben Scott](https://blog.ippon.tech/author/ben-scott)

September 15, 2020

![SOLID: A refactoring example](https://blog.ippon.tech/hubfs/Imported_Blog_Media/SOLID_Refactoring-3.png)

[Software Craftsmanship](https://blog.ippon.tech/tag/software-craftsmanship/)

 

<iframe id="{&quot;xdOrigin&quot;:&quot;https://blog.ippon.tech&quot;,&quot;xdChannel&quot;:&quot;2dfbfeca-cead-4108-ba64-b276fbc34611&quot;,&quot;framework&quot;:&quot;@linkedin/xdoor-sdk&quot;,&quot;version&quot;:&quot;0.1.176&quot;,&quot;debug&quot;:false}" class="IN-widget IN-widget--iframe" style="vertical-align: bottom; margin: 0px auto; display: block;" title="LinkedIn Embedded Content" xml="lang" src="https://www.linkedin.com/cws/member/public_profile?public_profile_url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fbenscott-agile-coach%2F&amp;format=inline&amp;related=false&amp;width=286&amp;xdOrigin=https%3A%2F%2Fblog.ippon.tech&amp;xdChannel=2dfbfeca-cead-4108-ba64-b276fbc34611&amp;xd_origin_host=https%3A%2F%2Fblog.ippon.tech" name="{&quot;xdOrigin&quot;:&quot;https://blog.ippon.tech&quot;,&quot;xdChannel&quot;:&quot;2dfbfeca-cead-4108-ba64-b276fbc34611&quot;,&quot;framework&quot;:&quot;@linkedin/xdoor-sdk&quot;,&quot;version&quot;:&quot;0.1.176&quot;,&quot;debug&quot;:false}" width="1" height="1" frameborder="0" scrolling="no"></iframe>

September 15, 2020

 

[SOLID](https://springframework.guru/solid-principles-object-oriented-programming/?ref=blog.ippon.tech) principles have been around for a long time and there's multiple articles out there explaining it, so why do yet another article? This blog isn't really meant to teach you SOLID principles but to provide an example based on a simplified real world example I ran into while working on a Spring Boot application.

## Legacy code

```
@Service
public class BadAccountService {

    public static final String MESSAGE = "You've been notified!";
    private EmailNotificationService emailNotificationService;
    private SmsNotificationService smsNotificationService;

    public BadAccountService(EmailNotificationService emailNotificationService,
                             SmsNotificationService smsNotificationService) {
        this.emailNotificationService = emailNotificationService;
        this.smsNotificationService = smsNotificationService;
    }

    public void notifyAccount(Account account) {

        switch (account.getNotificationPreference()) {
            case "sms":
              smsNotificationService.notify(account.getName(), MESSAGE);
              break;
            case "email":
            default:
              emailNotificationService.notify(account.getName(), MESSAGE);
        }
    }
}
```

Let's break this down a bit, we have an `AccountService` that has a notify method that intends to send a message to the account holder based on his preference. Email, or SMS. The good part of this code is that SMS notification is implemented in a different class than Email notification (**Single Responsibility** principle). The best part of this code is that it is easily testable, due to its usage of dependency injection, here's a simple test case:

```
@Test
void badAccountNotificationTest() {
   Account emailPreference = new Account("Ben", "email");
   Account smsPreference = new Account("Cecilia", "sms");
   Account unknownPreference = new Account("John", "unknown");

   badAccountService.notifyAccount(emailPreference);
   badAccountService.notifyAccount(smsPreference);
   badAccountService.notifyAccount(unknownPreference);

  verify(emailNotificationService, times(1))
         .notify("Ben", "You've been notified!");

  verify(smsNotificationService, times(1))
         .notify("Cecilia", "You've been notified!");

  verify(emailNotificationService, times(1))
         .notify("John", "You've been notified!");
    }
```

The bad part is that the notifyAccount method uses the two notification services directly, and uses a switch statement to direct the flow with the notification preference which violates the **Open/Close** principle. If we wanted to add a third notification preference we'd have to change the switch statement.

## Refactoring

First thing is to extract an interface from the notification services and make the notification services implement it:

```
public interface NotificationService {
    void notify(String person, String message);
}
```

Then we'll need a Factory to remove the need for a switch:

```
@Component
public class NotificationFactory {

    private Map<String, NotificationService> notificationServices;
    private EmailNotificationService defaultNotificationService;

    public NotificationFactory(Map<String, NotificationService> notificationServices, EmailNotificationService defaultNotificationService){
        this.notificationServices = notificationServices;
        this.defaultNotificationService = defaultNotificationService;
    }

    public Optional<NotificationService> getNotificationService(String type) {
         return Optional.ofNullable(notificationServices.get(type));
    }

    public NotificationService getDefaultNotificationService() {
        return defaultNotificationService;
    }
}
```

This Factory provides two ways of getting a notification service: The default notification, which requires `EmailNotificationService` to be injected directly and a way to look up a notification by it's name. This lookup deserves a deeper dive.

With Spring you can inject a list or a map of Spring components that implement an interface. Our map will have the the following elements:

- email -\> `EmailNotificationService`
- sms -\> `SmsNotificationService`

The String portion of the map is grabbed from the spring service's name:

```
@Service("email")
public class EmailNotificationService implements NotificationService {

    private static final Logger log = LoggerFactory.getLogger(EmailNotificationService.class);

    @Override
    public void notify(String person, String message) {
        log.info("{} has been notified with message: {}", person, message);
    }
}
```

```
@Service("sms")
public class SmsNotificationService implements NotificationService {

    private static final Logger log = LoggerFactory.getLogger(SmsNotificationService.class);

    @Override
    public void notify(String person, String message) {
        log.info("{} has been notified with message: {}", person, message);
    }
}
```

Finally we can refactor our `AccountService` class:

```
@Service
public class AccountService {

    private NotificationFactory notificationFactory;

    public AccountService(NotificationFactory notificationFactory) {
        this.notificationFactory = notificationFactory;
    }

    public void notifyAccount(Account account) {
        notificationFactory
         .getNotificationService(account.getNotificationPreference())
         .orElseGet(notificationFactory::getDefaultNotificationService)
         .notify(account.getName(), "You've been notified!");
    }
}
```

So what did we accomplish?

We've introduced a Factory which solves our main issue, the violation of the **Open/Close** principle. We can now add or remove notification services without impacting `AccountService`. The only change that we may need to make in the future would be to change the default notification service, however this implementation is much better than the `default` switch case.

We've decoupled the different notification services from the `AccountService` and it now only depends on the `NotificationFactory`, and expressed the default notification method in a more explicit way than a switch fall through.

The test method is actually unchanged, so we were able to do all this without changing our test.

You can find the [source code here](https://github.com/bescott1/SOLID-example?ref=blog.ippon.tech).

## Related Articles

##### [![Getting Your Application Started With WebFlux](https://blog.ippon.tech/hs-fs/hubfs/Webflux%20image%20(1).png?width=520&height=294&name=Webflux%20image%20(1).png) Spring • May 7, 2024 Getting Your Application Started With WebFlux 6 min read](https://blog.ippon.tech/getting-your-application-started-with-webflux)

##### [![Webflux - Starting your journey](https://blog.ippon.tech/hs-fs/hubfs/Untitled%20design.png?width=520&height=294&name=Untitled%20design.png) Ippon • March 19, 2024 Webflux - Starting your journey 6 min read](https://blog.ippon.tech/webflux-starting-your-journey)

##### [![Python in Production (Part 5 of 5)](https://blog.ippon.tech/hs-fs/hubfs/Imported_Blog_Media/Screenshot-2023-03-29-at-12_21_28-PM-3.png?width=520&height=294&name=Screenshot-2023-03-29-at-12_21_28-PM-3.png) Python • June 24, 2023 Python in Production (Part 5 of 5) 8 min read](https://blog.ippon.tech/python-in-production-part-5-of-5)

### Comments

### Subscribe to Our Blog!

Stay informed with the latest insights and updates by signing up for our weekly blog newsletter – delivered straight to your inbox!

[Back to blog homepage »](https://blog.ippon.tech/)

![IpponLogoKleinBlue](https://blog.ippon.tech/hs-fs/hubfs/IpponLogoKleinBlue.png?width=247&height=73&name=IpponLogoKleinBlue.png "IpponLogoKleinBlue")

Ippon is a consulting and expertise firm, who is convinced that technology is a source of progress for society. We help our clients leverage their digital assets to design an appropriate strategy and deploy their transformation roadmap at scale.

#### Navigation

- [Home](https://ipponusa.com/)
- [About](https://ipponusa.com/about-us/)
- [Services](https://ipponusa.com/services/)
- [Blogs](https://blog.ippon.tech/?__hstc=223043268.1036d82247623b329dfefe4e92697801.1714729179243.1714729179243.1714729179243.1&__hssc=223043268.2.1714729179244&__hsfp=803678701)
- [eBooks](https://ipponusa.com/ebooks/)
- [The Data Pour](https://info.ippon.tech/the-data-pour?__hstc=223043268.1036d82247623b329dfefe4e92697801.1714729179243.1714729179243.1714729179243.1&__hssc=223043268.2.1714729179244&__hsfp=803678701)

[Contact Us](https://ipponusa.com/contact/)

[Join Us](https://ipponusa.com/careers/)

#### Services

- [Data & Analytics](https://ipponusa.com/service/data-analytics/)
- [Cloud Strategy](https://ipponusa.com/service/cloud-strategy/)
- [Artificial Intelligence](https://ipponusa.com/service/artificial-intelligence/)
- [Operating Model](https://ipponusa.com/service/operating-model/)
- [Platform Modernization](https://ipponusa.com/service/platform-moderization/)
- [Product Innovation](https://ipponusa.com/service/product-innovation/)

#### Ippon International

- [France](https://fr.ippon.tech/?__hstc=223043268.1036d82247623b329dfefe4e92697801.1714729179243.1714729179243.1714729179243.1&__hssc=223043268.2.1714729179244&__hsfp=803678701)
- [Australia](https://au.ippon.tech/?__hstc=223043268.1036d82247623b329dfefe4e92697801.1714729179243.1714729179243.1714729179243.1&__hssc=223043268.2.1714729179244&__hsfp=803678701)

- #### Contact
- Ippon Technologies  
  [3431 West Leigh Street Richmond, VA 23230, USA](https://maps.app.goo.gl/RySm6SAwZnsxeiLz9)
-  
- [(844) 477- 6687](tel:8444776687)
-  
- [Sales@ipponusa.com](mailto:Sales@ipponusa.com)

<https://www.facebook.com/IpponUSA/> <https://www.youtube.com/c/ipponusa> <https://www.linkedin.com/company/ippon-technology>

©Copyright 2024 Ippon USA. All Rights Reserved.   |   [Terms and Conditions](https://ipponusa.com/privacy-policy/)   |   [Privacy Policy](https://ipponusa.com/privacy-policy/)   |   [Website by Skol Marketing](https://skolmarketing.com/)

```json
{
  "@context" : "https://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Ben Scott",
    "url" : "https://blog.ippon.tech/author/ben-scott"
  },
  "dateModified" : "2024-01-29T16:57:15.265Z",
  "datePublished" : "2020-09-15T12:57:00.000Z",
  "headline" : "SOLID: A refactoring example",
  "image" : [ "https://blog.ippon.tech/hubfs/Imported_Blog_Media/SOLID_Refactoring-3.png" ],
  "mainEntityOfPage" : {
    "@id" : "https://blog.ippon.tech/refactoring-to-solid",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://blog.ippon.tech/hubfs/logo_SVG.svg"
    },
    "name" : "Ippon Technologies"
  }
}
```