Software Architecture Design Patterns (4 Part Series)
1 #28.1 Part 1/3 Basics of Software Architecture and Design Patterns
2 #28.2 Part 2/3 Basics of Software Architecture and Design Patterns
3 #28.3 Part 3/3 Basics of Software Architecture and Design Patterns
4 Transformig a Fintech Investment Platform: From PHP to Java (Spring Boot)
Project Overview
Legacy code can be a major challenge for fintech platforms, particularly when dealing with aging PHP systems that are difficult to maintain and scale. To address these issues, we refactored an investment platform from PHP to Java, leveraging Spring Boot and SOAP-based APIs for improved reliability, performance, and maintainability.
In this article, we will walk through the design patterns used, the project structure, and key code examples—all in a way that even those without deep software development experience can understand.
Key Objectives
Why Refactor from PHP to Java?
PHP is widely used for web applications but can present challenges when scaling enterprise-grade financial platforms. The main reasons for refactoring include:
️ Improved Maintainability – Java’s object-oriented nature makes managing large codebases easier.
️ Performance Optimization – Java is better suited for high-performance applications with large-scale transactions.
️ Better Security – Java provides strong security features, which are crucial in fintech applications.
️ Scalability – Spring Boot enables microservice architecture, allowing for better modularity and scaling.
To facilitate a smooth transition, we designed a new platform structure incorporating design patterns that promote clean, reusable, and scalable code. Also the API’s are designed in Java using SOAP protocol.
Full Project Template with SOAP API Implementation (Java + Spring Boot)
This comprehensive manual will guide you through building the new investment platform using Java (Spring Boot) with SOAP API endpoints and the design patterns we discussed.
Project Structure
investment-platform/├── src/│ └── main/│ └── java/│ └── com/│ └── investment/│ ├── adapter/│ │ ├── BankAAdapter.java│ │ └── BankBAdapter.java│ ├── config/│ │ └── SOAPConfig.java│ ├── controller/│ │ └── InvestmentController.java│ ├── facade/│ │ └── BankServiceFacade.java│ ├── model/│ │ └── Client.java│ ├── repository/│ │ └── ClientRepository.java│ ├── service/│ │ ├── InvestmentService.java│ │ └── MarketDataService.java│ ├── soap/│ │ ├── BankAPI.java│ │ └── SOAPClient.java│ ├── strategy/│ │ ├── CompoundInterestStrategy.java│ │ └── SimpleInterestStrategy.java│ └── InvestmentPlatformApplication.java└── pom.xmlinvestment-platform/ ├── src/ │ └── main/ │ └── java/ │ └── com/ │ └── investment/ │ ├── adapter/ │ │ ├── BankAAdapter.java │ │ └── BankBAdapter.java │ ├── config/ │ │ └── SOAPConfig.java │ ├── controller/ │ │ └── InvestmentController.java │ ├── facade/ │ │ └── BankServiceFacade.java │ ├── model/ │ │ └── Client.java │ ├── repository/ │ │ └── ClientRepository.java │ ├── service/ │ │ ├── InvestmentService.java │ │ └── MarketDataService.java │ ├── soap/ │ │ ├── BankAPI.java │ │ └── SOAPClient.java │ ├── strategy/ │ │ ├── CompoundInterestStrategy.java │ │ └── SimpleInterestStrategy.java │ └── InvestmentPlatformApplication.java └── pom.xmlinvestment-platform/ ├── src/ │ └── main/ │ └── java/ │ └── com/ │ └── investment/ │ ├── adapter/ │ │ ├── BankAAdapter.java │ │ └── BankBAdapter.java │ ├── config/ │ │ └── SOAPConfig.java │ ├── controller/ │ │ └── InvestmentController.java │ ├── facade/ │ │ └── BankServiceFacade.java │ ├── model/ │ │ └── Client.java │ ├── repository/ │ │ └── ClientRepository.java │ ├── service/ │ │ ├── InvestmentService.java │ │ └── MarketDataService.java │ ├── soap/ │ │ ├── BankAPI.java │ │ └── SOAPClient.java │ ├── strategy/ │ │ ├── CompoundInterestStrategy.java │ │ └── SimpleInterestStrategy.java │ └── InvestmentPlatformApplication.java └── pom.xml
Enter fullscreen mode Exit fullscreen mode
The project structure explained:
The investment-platform project follows a structured layered architecture where each folder serves a specific purpose. This approach separates concerns, making the system more scalable, maintainable, and testable.
Here’s what each folder does and why it exists:
1️⃣ adapter/
– Bank API Integration (Adapter Pattern)
Purpose: Contains classes that allow the platform to interact with different banks’ APIs by converting their responses into a standard format.
Why is it needed?
- Different banks have different API structures (some return XML, some JSON).
- The Adapter Pattern standardizes these interactions so the main system doesn’t need to change when adding a new bank.
Example Files:
-
BankAAdapter.java
– Handles API calls to Bank A. -
BankBAdapter.java
– Handles API calls to Bank B.
2️⃣ config/
– Configuration Settings
Purpose: Contains configuration-related files, such as SOAP API settings and database connection properties.
Why is it needed?
- Centralizes configuration, keeping it separate from the main business logic.
- Allows for easy modifications without affecting core application code.
Example Files:
-
SOAPConfig.java
– Configures the SOAP API client.
3️⃣ controller/
– REST API Endpoints
Purpose: Defines REST API endpoints that external clients (web apps, mobile apps) interact with.
Why is it needed?
- Separates the API layer from the service logic.
- Handles HTTP requests and forwards them to the appropriate service.
Example Files:
-
InvestmentController.java
– Handles requests related to investment calculations and bank balances.
4️⃣ facade/
– Simplifying Complex Bank Interactions (Facade Pattern)
Purpose: Acts as a single point of interaction for multiple banks.
Why is it needed?
- If a user needs account balances from multiple banks, instead of calling each bank separately, the Facade Pattern provides a unified method.
- Simplifies interactions between different bank APIs.
Example Files:
-
BankServiceFacade.java
– CallsBankAAdapter
andBankBAdapter
and returns consolidated balances.
5️⃣ model/
– Data Objects (Entities)
Purpose: Defines Java objects that represent database entities.
Why is it needed?
- Keeps the data structure centralized.
- Helps in mapping database tables to Java objects.
Example Files:
-
Client.java
– Represents an investor with attributes likeid
,name
, andinvestmentType
.
6️⃣ repository/
– Database Access (Repository Pattern)
Purpose: Defines database operations using Spring Data JPA.
Why is it needed?
- Encapsulates database queries so that other parts of the app don’t need to worry about database logic.
- Uses the Repository Pattern for easy database access.
Example Files:
-
ClientRepository.java
– Provides methods to fetch Client data from the database.
7️⃣ service/
– Business Logic
Purpose: Contains the core logic of the investment platform, such as investment calculations and bank interactions.
Why is it needed?
- Separates business logic from controllers (API layer).
- Promotes reusability—controllers and other services can call these methods.
Example Files:
-
InvestmentService.java
– Handles investment calculations and retrieves bank balances. -
MarketDataService.java
– Tracks market changes (for future real-time updates).
8️⃣ soap/
– SOAP API Clients
Purpose: Handles SOAP-based API communication with external bank services.
Why is it needed?
- SOAP APIs require special handling (e.g., XML parsing).
- The SOAPClient class ensures efficient API calls using the Singleton Pattern.
Example Files:
-
SOAPClient.java
– A singleton class that manages SOAP API requests. -
BankAPI.java
– An interface defining methods for interacting with different banks.
9️⃣ strategy/
– Investment Calculation Strategies (Strategy Pattern)
Purpose: Contains different investment calculation methods, such as compound interest and simple interest.
Why is it needed?
- Users may want different investment models.
- The Strategy Pattern allows switching between different calculation strategies dynamically.
Example Files:
-
InvestmentStrategy.java
– Defines the contract for all strategies. -
CompoundInterestStrategy.java
– Implements compound interest calculations. -
SimpleInterestStrategy.java
– Implements simple interest calculations.
InvestmentPlatformApplication.java
– The Main Entry Point
Purpose: This is the main class where the Spring Boot application starts.
Why is it needed?
- The
@SpringBootApplication
annotation automatically configures the app. - It runs the entire platform as a Spring Boot service.
Example File:
-
InvestmentPlatformApplication.java
– Contains themain()
method.
By structuring the platform this way, we achieve:
Separation of Concerns – Each folder has a clear responsibility.
Scalability – New features can be added without modifying the entire system.
Maintainability – Developers can quickly understand and modify the project.
Key Takeaways from the Structure
- Separation of Concerns – Each feature is isolated in its own folder.
- Extensibility – The platform supports multiple banks using an Adapter Pattern.
- Scalability – Future services can be added without disrupting existing functionality.
Let’s see how the theory would be used in a real-world scenario.
1. Initialize a Spring Boot Project
Create the project using Spring Initializr:
- Dependencies: Spring Web, Spring Boot Starter SOAP, Spring Boot Starter Data JPA, Spring Boot Starter Web Services, Lombok, MySQL Driver This setup includes:
- Spring Boot Web – To build REST APIs.
- Spring Boot Web Services – To handle SOAP-based APIs.
- Spring Data JPA – To manage database transactions with MySQL.
pom.xml
<span><project></span><span><modelVersion></span>4.0.0<span></modelVersion></span><span><groupId></span>com.investment<span></groupId></span><span><artifactId></span>investment-platform<span></artifactId></span><span><version></span>1.0.0<span></version></span><span><dependencies></span><span><dependency></span><span><groupId></span>org.springframework.boot<span></groupId></span><span><artifactId></span>spring-boot-starter-web<span></artifactId></span><span></dependency></span><span><dependency></span><span><groupId></span>org.springframework.boot<span></groupId></span><span><artifactId></span>spring-boot-starter-web-services<span></artifactId></span><span></dependency></span><span><dependency></span><span><groupId></span>org.springframework.boot<span></groupId></span><span><artifactId></span>spring-boot-starter-data-jpa<span></artifactId></span><span></dependency></span><span><dependency></span><span><groupId></span>mysql<span></groupId></span><span><artifactId></span>mysql-connector-java<span></artifactId></span><span></dependency></span><span><dependency></span><span><groupId></span>org.springframework.boot<span></groupId></span><span><artifactId></span>spring-boot-starter-actuator<span></artifactId></span><span></dependency></span><span><dependency></span><span><groupId></span>org.projectlombok<span></groupId></span><span><artifactId></span>lombok<span></artifactId></span><span><scope></span>provided<span></scope></span><span></dependency></span><span></dependencies></span><span><build></span><span><plugins></span><span><plugin></span><span><groupId></span>org.springframework.boot<span></groupId></span><span><artifactId></span>spring-boot-maven-plugin<span></artifactId></span><span></plugin></span><span></plugins></span><span></build></span><span></project></span><span><project></span> <span><modelVersion></span>4.0.0<span></modelVersion></span> <span><groupId></span>com.investment<span></groupId></span> <span><artifactId></span>investment-platform<span></artifactId></span> <span><version></span>1.0.0<span></version></span> <span><dependencies></span> <span><dependency></span> <span><groupId></span>org.springframework.boot<span></groupId></span> <span><artifactId></span>spring-boot-starter-web<span></artifactId></span> <span></dependency></span> <span><dependency></span> <span><groupId></span>org.springframework.boot<span></groupId></span> <span><artifactId></span>spring-boot-starter-web-services<span></artifactId></span> <span></dependency></span> <span><dependency></span> <span><groupId></span>org.springframework.boot<span></groupId></span> <span><artifactId></span>spring-boot-starter-data-jpa<span></artifactId></span> <span></dependency></span> <span><dependency></span> <span><groupId></span>mysql<span></groupId></span> <span><artifactId></span>mysql-connector-java<span></artifactId></span> <span></dependency></span> <span><dependency></span> <span><groupId></span>org.springframework.boot<span></groupId></span> <span><artifactId></span>spring-boot-starter-actuator<span></artifactId></span> <span></dependency></span> <span><dependency></span> <span><groupId></span>org.projectlombok<span></groupId></span> <span><artifactId></span>lombok<span></artifactId></span> <span><scope></span>provided<span></scope></span> <span></dependency></span> <span></dependencies></span> <span><build></span> <span><plugins></span> <span><plugin></span> <span><groupId></span>org.springframework.boot<span></groupId></span> <span><artifactId></span>spring-boot-maven-plugin<span></artifactId></span> <span></plugin></span> <span></plugins></span> <span></build></span> <span></project></span><project> <modelVersion>4.0.0</modelVersion> <groupId>com.investment</groupId> <artifactId>investment-platform</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Enter fullscreen mode Exit fullscreen mode
️ 2. Configuration
application.properties
<span>server.port</span><span>=</span><span>8080</span><span>spring.datasource.url</span><span>=</span><span>jdbc:mysql://localhost:3306/investment_db</span><span>spring.datasource.username</span><span>=</span><span>root</span><span>spring.datasource.password</span><span>=</span><span>secret</span><span>spring.jpa.hibernate.ddl-auto</span><span>=</span><span>update</span><span>spring.jpa.show-sql</span><span>=</span><span>true</span><span>spring.jpa.database-platform</span><span>=</span><span>org.hibernate.dialect.MySQLDialect</span><span>server.port</span><span>=</span><span>8080</span> <span>spring.datasource.url</span><span>=</span><span>jdbc:mysql://localhost:3306/investment_db</span> <span>spring.datasource.username</span><span>=</span><span>root</span> <span>spring.datasource.password</span><span>=</span><span>secret</span> <span>spring.jpa.hibernate.ddl-auto</span><span>=</span><span>update</span> <span>spring.jpa.show-sql</span><span>=</span><span>true</span> <span>spring.jpa.database-platform</span><span>=</span><span>org.hibernate.dialect.MySQLDialect</span>server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/investment_db spring.datasource.username=root spring.datasource.password=secret spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
Enter fullscreen mode Exit fullscreen mode
SOAPConfig.java
<span>package</span> <span>com.investment.config</span><span>;</span><span>import</span> <span>org.springframework.context.annotation.Bean</span><span>;</span><span>import</span> <span>org.springframework.context.annotation.Configuration</span><span>;</span><span>import</span> <span>org.springframework.oxm.jaxb.Jaxb2Marshaller</span><span>;</span><span>@Configuration</span><span>public</span> <span>class</span> <span>SOAPConfig</span> <span>{</span><span>@Bean</span><span>public</span> <span>Jaxb2Marshaller</span> <span>marshaller</span><span>()</span> <span>{</span><span>Jaxb2Marshaller</span> <span>marshaller</span> <span>=</span> <span>new</span> <span>Jaxb2Marshaller</span><span>();</span><span>marshaller</span><span>.</span><span>setContextPath</span><span>(</span><span>"com.investment.soap"</span><span>);</span><span>return</span> <span>marshaller</span><span>;</span><span>}</span><span>}</span><span>package</span> <span>com.investment.config</span><span>;</span> <span>import</span> <span>org.springframework.context.annotation.Bean</span><span>;</span> <span>import</span> <span>org.springframework.context.annotation.Configuration</span><span>;</span> <span>import</span> <span>org.springframework.oxm.jaxb.Jaxb2Marshaller</span><span>;</span> <span>@Configuration</span> <span>public</span> <span>class</span> <span>SOAPConfig</span> <span>{</span> <span>@Bean</span> <span>public</span> <span>Jaxb2Marshaller</span> <span>marshaller</span><span>()</span> <span>{</span> <span>Jaxb2Marshaller</span> <span>marshaller</span> <span>=</span> <span>new</span> <span>Jaxb2Marshaller</span><span>();</span> <span>marshaller</span><span>.</span><span>setContextPath</span><span>(</span><span>"com.investment.soap"</span><span>);</span> <span>return</span> <span>marshaller</span><span>;</span> <span>}</span> <span>}</span>package com.investment.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.oxm.jaxb.Jaxb2Marshaller; @Configuration public class SOAPConfig { @Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setContextPath("com.investment.soap"); return marshaller; } }
Enter fullscreen mode Exit fullscreen mode
3. SOAP Client with Singleton Pattern
SOAPClient.java
<span>package</span> <span>com.investment.soap</span><span>;</span><span>import</span> <span>javax.xml.soap.*</span><span>;</span><span>public</span> <span>class</span> <span>SOAPClient</span> <span>{</span><span>private</span> <span>static</span> <span>SOAPClient</span> <span>instance</span><span>;</span><span>private</span> <span>SOAPConnection</span> <span>connection</span><span>;</span><span>private</span> <span>SOAPClient</span><span>()</span> <span>throws</span> <span>SOAPException</span> <span>{</span><span>SOAPConnectionFactory</span> <span>factory</span> <span>=</span> <span>SOAPConnectionFactory</span><span>.</span><span>newInstance</span><span>();</span><span>connection</span> <span>=</span> <span>factory</span><span>.</span><span>createConnection</span><span>();</span><span>}</span><span>public</span> <span>static</span> <span>SOAPClient</span> <span>getInstance</span><span>()</span> <span>throws</span> <span>SOAPException</span> <span>{</span><span>if</span> <span>(</span><span>instance</span> <span>==</span> <span>null</span><span>)</span> <span>{</span><span>synchronized</span> <span>(</span><span>SOAPClient</span><span>.</span><span>class</span><span>)</span> <span>{</span><span>if</span> <span>(</span><span>instance</span> <span>==</span> <span>null</span><span>)</span> <span>{</span><span>instance</span> <span>=</span> <span>new</span> <span>SOAPClient</span><span>();</span><span>}</span><span>}</span><span>}</span><span>return</span> <span>instance</span><span>;</span><span>}</span><span>public</span> <span>SOAPMessage</span> <span>sendRequest</span><span>(</span><span>String</span> <span>endpointUrl</span><span>,</span> <span>SOAPMessage</span> <span>request</span><span>)</span> <span>throws</span> <span>SOAPException</span> <span>{</span><span>return</span> <span>connection</span><span>.</span><span>call</span><span>(</span><span>request</span><span>,</span> <span>endpointUrl</span><span>);</span><span>}</span><span>}</span><span>package</span> <span>com.investment.soap</span><span>;</span> <span>import</span> <span>javax.xml.soap.*</span><span>;</span> <span>public</span> <span>class</span> <span>SOAPClient</span> <span>{</span> <span>private</span> <span>static</span> <span>SOAPClient</span> <span>instance</span><span>;</span> <span>private</span> <span>SOAPConnection</span> <span>connection</span><span>;</span> <span>private</span> <span>SOAPClient</span><span>()</span> <span>throws</span> <span>SOAPException</span> <span>{</span> <span>SOAPConnectionFactory</span> <span>factory</span> <span>=</span> <span>SOAPConnectionFactory</span><span>.</span><span>newInstance</span><span>();</span> <span>connection</span> <span>=</span> <span>factory</span><span>.</span><span>createConnection</span><span>();</span> <span>}</span> <span>public</span> <span>static</span> <span>SOAPClient</span> <span>getInstance</span><span>()</span> <span>throws</span> <span>SOAPException</span> <span>{</span> <span>if</span> <span>(</span><span>instance</span> <span>==</span> <span>null</span><span>)</span> <span>{</span> <span>synchronized</span> <span>(</span><span>SOAPClient</span><span>.</span><span>class</span><span>)</span> <span>{</span> <span>if</span> <span>(</span><span>instance</span> <span>==</span> <span>null</span><span>)</span> <span>{</span> <span>instance</span> <span>=</span> <span>new</span> <span>SOAPClient</span><span>();</span> <span>}</span> <span>}</span> <span>}</span> <span>return</span> <span>instance</span><span>;</span> <span>}</span> <span>public</span> <span>SOAPMessage</span> <span>sendRequest</span><span>(</span><span>String</span> <span>endpointUrl</span><span>,</span> <span>SOAPMessage</span> <span>request</span><span>)</span> <span>throws</span> <span>SOAPException</span> <span>{</span> <span>return</span> <span>connection</span><span>.</span><span>call</span><span>(</span><span>request</span><span>,</span> <span>endpointUrl</span><span>);</span> <span>}</span> <span>}</span>package com.investment.soap; import javax.xml.soap.*; public class SOAPClient { private static SOAPClient instance; private SOAPConnection connection; private SOAPClient() throws SOAPException { SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance(); connection = factory.createConnection(); } public static SOAPClient getInstance() throws SOAPException { if (instance == null) { synchronized (SOAPClient.class) { if (instance == null) { instance = new SOAPClient(); } } } return instance; } public SOAPMessage sendRequest(String endpointUrl, SOAPMessage request) throws SOAPException { return connection.call(request, endpointUrl); } }
Enter fullscreen mode Exit fullscreen mode
Why Singleton?
- Ensures only one SOAP connection exists, reducing memory usage.
- Prevents duplicate API requests, improving efficiency.
4. Adapter Pattern for Bank APIs
SOAP Interface for Banks
<span>package</span> <span>com.investment.soap</span><span>;</span><span>public</span> <span>interface</span> <span>BankAPI</span> <span>{</span><span>String</span> <span>getAccountBalance</span><span>(</span><span>String</span> <span>accountId</span><span>);</span><span>String</span> <span>transferFunds</span><span>(</span><span>String</span> <span>fromAccount</span><span>,</span> <span>String</span> <span>toAccount</span><span>,</span> <span>double</span> <span>amount</span><span>);</span><span>}</span><span>package</span> <span>com.investment.soap</span><span>;</span> <span>public</span> <span>interface</span> <span>BankAPI</span> <span>{</span> <span>String</span> <span>getAccountBalance</span><span>(</span><span>String</span> <span>accountId</span><span>);</span> <span>String</span> <span>transferFunds</span><span>(</span><span>String</span> <span>fromAccount</span><span>,</span> <span>String</span> <span>toAccount</span><span>,</span> <span>double</span> <span>amount</span><span>);</span> <span>}</span>package com.investment.soap; public interface BankAPI { String getAccountBalance(String accountId); String transferFunds(String fromAccount, String toAccount, double amount); }
Enter fullscreen mode Exit fullscreen mode
Bank A Adapter
<span>package</span> <span>com.investment.adapter</span><span>;</span><span>import</span> <span>com.investment.soap.BankAPI</span><span>;</span><span>public</span> <span>class</span> <span>BankAAdapter</span> <span>implements</span> <span>BankAPI</span> <span>{</span><span>@Override</span><span>public</span> <span>String</span> <span>getAccountBalance</span><span>(</span><span>String</span> <span>accountId</span><span>)</span> <span>{</span><span>// Simulate SOAP request to Bank A</span><span>return</span> <span>"<balance>10000.00</balance>"</span><span>;</span><span>}</span><span>@Override</span><span>public</span> <span>String</span> <span>transferFunds</span><span>(</span><span>String</span> <span>fromAccount</span><span>,</span> <span>String</span> <span>toAccount</span><span>,</span> <span>double</span> <span>amount</span><span>)</span> <span>{</span><span>return</span> <span>"BankA Transfer Successful"</span><span>;</span><span>}</span><span>}</span><span>package</span> <span>com.investment.adapter</span><span>;</span> <span>import</span> <span>com.investment.soap.BankAPI</span><span>;</span> <span>public</span> <span>class</span> <span>BankAAdapter</span> <span>implements</span> <span>BankAPI</span> <span>{</span> <span>@Override</span> <span>public</span> <span>String</span> <span>getAccountBalance</span><span>(</span><span>String</span> <span>accountId</span><span>)</span> <span>{</span> <span>// Simulate SOAP request to Bank A</span> <span>return</span> <span>"<balance>10000.00</balance>"</span><span>;</span> <span>}</span> <span>@Override</span> <span>public</span> <span>String</span> <span>transferFunds</span><span>(</span><span>String</span> <span>fromAccount</span><span>,</span> <span>String</span> <span>toAccount</span><span>,</span> <span>double</span> <span>amount</span><span>)</span> <span>{</span> <span>return</span> <span>"BankA Transfer Successful"</span><span>;</span> <span>}</span> <span>}</span>package com.investment.adapter; import com.investment.soap.BankAPI; public class BankAAdapter implements BankAPI { @Override public String getAccountBalance(String accountId) { // Simulate SOAP request to Bank A return "<balance>10000.00</balance>"; } @Override public String transferFunds(String fromAccount, String toAccount, double amount) { return "BankA Transfer Successful"; } }
Enter fullscreen mode Exit fullscreen mode
Why Adapter Pattern?
- Allows the system to integrate with multiple bank APIs without modifying the core code.
- Ensures smooth switching between different banks.
5. Facade Pattern for Multiple Banks
BankServiceFacade.java
<span>package</span> <span>com.investment.facade</span><span>;</span><span>import</span> <span>com.investment.soap.BankAPI</span><span>;</span><span>public</span> <span>class</span> <span>BankServiceFacade</span> <span>{</span><span>private</span> <span>final</span> <span>BankAPI</span> <span>bankAAdapter</span><span>;</span><span>private</span> <span>final</span> <span>BankAPI</span> <span>bankBAdapter</span><span>;</span><span>public</span> <span>BankServiceFacade</span><span>(</span><span>BankAPI</span> <span>bankAAdapter</span><span>,</span> <span>BankAPI</span> <span>bankBAdapter</span><span>)</span> <span>{</span><span>this</span><span>.</span><span>bankAAdapter</span> <span>=</span> <span>bankAAdapter</span><span>;</span><span>this</span><span>.</span><span>bankBAdapter</span> <span>=</span> <span>bankBAdapter</span><span>;</span><span>}</span><span>public</span> <span>String</span> <span>getConsolidatedBalance</span><span>(</span><span>String</span> <span>accountId</span><span>)</span> <span>{</span><span>String</span> <span>balanceA</span> <span>=</span> <span>bankAAdapter</span><span>.</span><span>getAccountBalance</span><span>(</span><span>accountId</span><span>);</span><span>String</span> <span>balanceB</span> <span>=</span> <span>bankBAdapter</span><span>.</span><span>getAccountBalance</span><span>(</span><span>accountId</span><span>);</span><span>return</span> <span>"BankA: "</span> <span>+</span> <span>balanceA</span> <span>+</span> <span>", BankB: "</span> <span>+</span> <span>balanceB</span><span>;</span><span>}</span><span>}</span><span>package</span> <span>com.investment.facade</span><span>;</span> <span>import</span> <span>com.investment.soap.BankAPI</span><span>;</span> <span>public</span> <span>class</span> <span>BankServiceFacade</span> <span>{</span> <span>private</span> <span>final</span> <span>BankAPI</span> <span>bankAAdapter</span><span>;</span> <span>private</span> <span>final</span> <span>BankAPI</span> <span>bankBAdapter</span><span>;</span> <span>public</span> <span>BankServiceFacade</span><span>(</span><span>BankAPI</span> <span>bankAAdapter</span><span>,</span> <span>BankAPI</span> <span>bankBAdapter</span><span>)</span> <span>{</span> <span>this</span><span>.</span><span>bankAAdapter</span> <span>=</span> <span>bankAAdapter</span><span>;</span> <span>this</span><span>.</span><span>bankBAdapter</span> <span>=</span> <span>bankBAdapter</span><span>;</span> <span>}</span> <span>public</span> <span>String</span> <span>getConsolidatedBalance</span><span>(</span><span>String</span> <span>accountId</span><span>)</span> <span>{</span> <span>String</span> <span>balanceA</span> <span>=</span> <span>bankAAdapter</span><span>.</span><span>getAccountBalance</span><span>(</span><span>accountId</span><span>);</span> <span>String</span> <span>balanceB</span> <span>=</span> <span>bankBAdapter</span><span>.</span><span>getAccountBalance</span><span>(</span><span>accountId</span><span>);</span> <span>return</span> <span>"BankA: "</span> <span>+</span> <span>balanceA</span> <span>+</span> <span>", BankB: "</span> <span>+</span> <span>balanceB</span><span>;</span> <span>}</span> <span>}</span>package com.investment.facade; import com.investment.soap.BankAPI; public class BankServiceFacade { private final BankAPI bankAAdapter; private final BankAPI bankBAdapter; public BankServiceFacade(BankAPI bankAAdapter, BankAPI bankBAdapter) { this.bankAAdapter = bankAAdapter; this.bankBAdapter = bankBAdapter; } public String getConsolidatedBalance(String accountId) { String balanceA = bankAAdapter.getAccountBalance(accountId); String balanceB = bankBAdapter.getAccountBalance(accountId); return "BankA: " + balanceA + ", BankB: " + balanceB; } }
Enter fullscreen mode Exit fullscreen mode
Why Facade Pattern?
- Reduces complexity by exposing a single method for fetching balances.
- Improves code readability.
6. Strategy Pattern for Investment Calculations
InvestmentStrategy.java
<span>package</span> <span>com.investment.strategy</span><span>;</span><span>public</span> <span>interface</span> <span>InvestmentStrategy</span> <span>{</span><span>double</span> <span>calculateReturn</span><span>(</span><span>double</span> <span>principal</span><span>,</span> <span>double</span> <span>rate</span><span>,</span> <span>int</span> <span>years</span><span>);</span><span>}</span><span>package</span> <span>com.investment.strategy</span><span>;</span> <span>public</span> <span>interface</span> <span>InvestmentStrategy</span> <span>{</span> <span>double</span> <span>calculateReturn</span><span>(</span><span>double</span> <span>principal</span><span>,</span> <span>double</span> <span>rate</span><span>,</span> <span>int</span> <span>years</span><span>);</span> <span>}</span>package com.investment.strategy; public interface InvestmentStrategy { double calculateReturn(double principal, double rate, int years); }
Enter fullscreen mode Exit fullscreen mode
CompoundInterestStrategy.java
<span>package</span> <span>com.investment.strategy</span><span>;</span><span>public</span> <span>class</span> <span>CompoundInterestStrategy</span> <span>implements</span> <span>InvestmentStrategy</span> <span>{</span><span>@Override</span><span>public</span> <span>double</span> <span>calculateReturn</span><span>(</span><span>double</span> <span>principal</span><span>,</span> <span>double</span> <span>rate</span><span>,</span> <span>int</span> <span>years</span><span>)</span> <span>{</span><span>return</span> <span>principal</span> <span>*</span> <span>Math</span><span>.</span><span>pow</span><span>((</span><span>1</span> <span>+</span> <span>rate</span> <span>/</span> <span>100</span><span>),</span> <span>years</span><span>);</span><span>}</span><span>}</span><span>package</span> <span>com.investment.strategy</span><span>;</span> <span>public</span> <span>class</span> <span>CompoundInterestStrategy</span> <span>implements</span> <span>InvestmentStrategy</span> <span>{</span> <span>@Override</span> <span>public</span> <span>double</span> <span>calculateReturn</span><span>(</span><span>double</span> <span>principal</span><span>,</span> <span>double</span> <span>rate</span><span>,</span> <span>int</span> <span>years</span><span>)</span> <span>{</span> <span>return</span> <span>principal</span> <span>*</span> <span>Math</span><span>.</span><span>pow</span><span>((</span><span>1</span> <span>+</span> <span>rate</span> <span>/</span> <span>100</span><span>),</span> <span>years</span><span>);</span> <span>}</span> <span>}</span>package com.investment.strategy; public class CompoundInterestStrategy implements InvestmentStrategy { @Override public double calculateReturn(double principal, double rate, int years) { return principal * Math.pow((1 + rate / 100), years); } }
Enter fullscreen mode Exit fullscreen mode
SimpleInterestStrategy.java
<span>package</span> <span>com.investment.strategy</span><span>;</span><span>public</span> <span>class</span> <span>SimpleInterestStrategy</span> <span>implements</span> <span>InvestmentStrategy</span> <span>{</span><span>@Override</span><span>public</span> <span>double</span> <span>calculateReturn</span><span>(</span><span>double</span> <span>principal</span><span>,</span> <span>double</span> <span>rate</span><span>,</span> <span>int</span> <span>years</span><span>)</span> <span>{</span><span>return</span> <span>principal</span> <span>+</span> <span>(</span><span>principal</span> <span>*</span> <span>rate</span> <span>*</span> <span>years</span> <span>/</span> <span>100</span><span>);</span><span>}</span><span>}</span><span>package</span> <span>com.investment.strategy</span><span>;</span> <span>public</span> <span>class</span> <span>SimpleInterestStrategy</span> <span>implements</span> <span>InvestmentStrategy</span> <span>{</span> <span>@Override</span> <span>public</span> <span>double</span> <span>calculateReturn</span><span>(</span><span>double</span> <span>principal</span><span>,</span> <span>double</span> <span>rate</span><span>,</span> <span>int</span> <span>years</span><span>)</span> <span>{</span> <span>return</span> <span>principal</span> <span>+</span> <span>(</span><span>principal</span> <span>*</span> <span>rate</span> <span>*</span> <span>years</span> <span>/</span> <span>100</span><span>);</span> <span>}</span> <span>}</span>package com.investment.strategy; public class SimpleInterestStrategy implements InvestmentStrategy { @Override public double calculateReturn(double principal, double rate, int years) { return principal + (principal * rate * years / 100); } }
Enter fullscreen mode Exit fullscreen mode
Why Strategy Pattern?
- Users can choose between compound interest or simple interest dynamically.
- Simplifies adding new investment strategies in the future.
7. Observer Pattern for Real-Time Market Updates
MarketDataService.java
<span>package</span> <span>com.investment.service</span><span>;</span><span>import</span> <span>java.util.ArrayList</span><span>;</span><span>import</span> <span>java.util.List</span><span>;</span><span>interface</span> <span>Observer</span> <span>{</span><span>void</span> <span>update</span><span>(</span><span>String</span> <span>marketUpdate</span><span>);</span><span>}</span><span>interface</span> <span>MarketData</span> <span>{</span><span>void</span> <span>addObserver</span><span>(</span><span>Observer</span> <span>observer</span><span>);</span><span>void</span> <span>removeObserver</span><span>(</span><span>Observer</span> <span>observer</span><span>);</span><span>void</span> <span>notifyObservers</span><span>(</span><span>String</span> <span>update</span><span>);</span><span>}</span><span>public</span> <span>class</span> <span>MarketDataService</span> <span>implements</span> <span>MarketData</span> <span>{</span><span>private</span> <span>final</span> <span>List</span><span><</span><span>Observer</span><span>></span> <span>observers</span> <span>=</span> <span>new</span> <span>ArrayList</span><span><>();</span><span>@Override</span><span>public</span> <span>void</span> <span>addObserver</span><span>(</span><span>Observer</span> <span>observer</span><span>)</span> <span>{</span><span>observers</span><span>.</span><span>add</span><span>(</span><span>observer</span><span>);</span><span>}</span><span>@Override</span><span>public</span> <span>void</span> <span>removeObserver</span><span>(</span><span>Observer</span> <span>observer</span><span>)</span> <span>{</span><span>observers</span><span>.</span><span>remove</span><span>(</span><span>observer</span><span>);</span><span>}</span><span>@Override</span><span>public</span> <span>void</span> <span>notifyObservers</span><span>(</span><span>String</span> <span>update</span><span>)</span> <span>{</span><span>for</span> <span>(</span><span>Observer</span> <span>observer</span> <span>:</span> <span>observers</span><span>)</span> <span>{</span><span>observer</span><span>.</span><span>update</span><span>(</span><span>update</span><span>);</span><span>}</span><span>}</span><span>}</span><span>package</span> <span>com.investment.service</span><span>;</span> <span>import</span> <span>java.util.ArrayList</span><span>;</span> <span>import</span> <span>java.util.List</span><span>;</span> <span>interface</span> <span>Observer</span> <span>{</span> <span>void</span> <span>update</span><span>(</span><span>String</span> <span>marketUpdate</span><span>);</span> <span>}</span> <span>interface</span> <span>MarketData</span> <span>{</span> <span>void</span> <span>addObserver</span><span>(</span><span>Observer</span> <span>observer</span><span>);</span> <span>void</span> <span>removeObserver</span><span>(</span><span>Observer</span> <span>observer</span><span>);</span> <span>void</span> <span>notifyObservers</span><span>(</span><span>String</span> <span>update</span><span>);</span> <span>}</span> <span>public</span> <span>class</span> <span>MarketDataService</span> <span>implements</span> <span>MarketData</span> <span>{</span> <span>private</span> <span>final</span> <span>List</span><span><</span><span>Observer</span><span>></span> <span>observers</span> <span>=</span> <span>new</span> <span>ArrayList</span><span><>();</span> <span>@Override</span> <span>public</span> <span>void</span> <span>addObserver</span><span>(</span><span>Observer</span> <span>observer</span><span>)</span> <span>{</span> <span>observers</span><span>.</span><span>add</span><span>(</span><span>observer</span><span>);</span> <span>}</span> <span>@Override</span> <span>public</span> <span>void</span> <span>removeObserver</span><span>(</span><span>Observer</span> <span>observer</span><span>)</span> <span>{</span> <span>observers</span><span>.</span><span>remove</span><span>(</span><span>observer</span><span>);</span> <span>}</span> <span>@Override</span> <span>public</span> <span>void</span> <span>notifyObservers</span><span>(</span><span>String</span> <span>update</span><span>)</span> <span>{</span> <span>for</span> <span>(</span><span>Observer</span> <span>observer</span> <span>:</span> <span>observers</span><span>)</span> <span>{</span> <span>observer</span><span>.</span><span>update</span><span>(</span><span>update</span><span>);</span> <span>}</span> <span>}</span> <span>}</span>package com.investment.service; import java.util.ArrayList; import java.util.List; interface Observer { void update(String marketUpdate); } interface MarketData { void addObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(String update); } public class MarketDataService implements MarketData { private final List<Observer> observers = new ArrayList<>(); @Override public void addObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers(String update) { for (Observer observer : observers) { observer.update(update); } } }
Enter fullscreen mode Exit fullscreen mode
8. Repository Pattern for Database Operations
Client Entity
<span>package</span> <span>com.investment.model</span><span>;</span><span>import</span> <span>lombok.Data</span><span>;</span><span>import</span> <span>javax.persistence.Entity</span><span>;</span><span>import</span> <span>javax.persistence.Id</span><span>;</span><span>@Entity</span><span>@Data</span><span>public</span> <span>class</span> <span>Client</span> <span>{</span><span>@Id</span><span>private</span> <span>String</span> <span>id</span><span>;</span><span>private</span> <span>String</span> <span>name</span><span>;</span><span>private</span> <span>String</span> <span>investmentType</span><span>;</span><span>}</span><span>package</span> <span>com.investment.model</span><span>;</span> <span>import</span> <span>lombok.Data</span><span>;</span> <span>import</span> <span>javax.persistence.Entity</span><span>;</span> <span>import</span> <span>javax.persistence.Id</span><span>;</span> <span>@Entity</span> <span>@Data</span> <span>public</span> <span>class</span> <span>Client</span> <span>{</span> <span>@Id</span> <span>private</span> <span>String</span> <span>id</span><span>;</span> <span>private</span> <span>String</span> <span>name</span><span>;</span> <span>private</span> <span>String</span> <span>investmentType</span><span>;</span> <span>}</span>package com.investment.model; import lombok.Data; import javax.persistence.Entity; import javax.persistence.Id; @Entity @Data public class Client { @Id private String id; private String name; private String investmentType; }
Enter fullscreen mode Exit fullscreen mode
Client Repository Interface
<span>package</span> <span>com.investment.repository</span><span>;</span><span>import</span> <span>com.investment.model.Client</span><span>;</span><span>import</span> <span>org.springframework.data.jpa.repository.JpaRepository</span><span>;</span><span>public</span> <span>interface</span> <span>ClientRepository</span> <span>extends</span> <span>JpaRepository</span><span><</span><span>Client</span><span>,</span> <span>String</span><span>></span> <span>{</span><span>}</span><span>package</span> <span>com.investment.repository</span><span>;</span> <span>import</span> <span>com.investment.model.Client</span><span>;</span> <span>import</span> <span>org.springframework.data.jpa.repository.JpaRepository</span><span>;</span> <span>public</span> <span>interface</span> <span>ClientRepository</span> <span>extends</span> <span>JpaRepository</span><span><</span><span>Client</span><span>,</span> <span>String</span><span>></span> <span>{</span> <span>}</span>package com.investment.repository; import com.investment.model.Client; import org.springframework.data.jpa.repository.JpaRepository; public interface ClientRepository extends JpaRepository<Client, String> { }
Enter fullscreen mode Exit fullscreen mode
9. Service Layer
InvestmentService.java
<span>package</span> <span>com.investment.service</span><span>;</span><span>import</span> <span>com.investment.facade.BankServiceFacade</span><span>;</span><span>import</span> <span>com.investment.strategy.InvestmentStrategy</span><span>;</span><span>import</span> <span>org.springframework.stereotype.Service</span><span>;</span><span>@Service</span><span>public</span> <span>class</span> <span>InvestmentService</span> <span>{</span><span>private</span> <span>final</span> <span>BankServiceFacade</span> <span>bankServiceFacade</span><span>;</span><span>private</span> <span>InvestmentStrategy</span> <span>strategy</span><span>;</span><span>public</span> <span>InvestmentService</span><span>(</span><span>BankServiceFacade</span> <span>bankServiceFacade</span><span>)</span> <span>{</span><span>this</span><span>.</span><span>bankServiceFacade</span> <span>=</span> <span>bankServiceFacade</span><span>;</span><span>}</span><span>public</span> <span>void</span> <span>setStrategy</span><span>(</span><span>InvestmentStrategy</span> <span>strategy</span><span>)</span> <span>{</span><span>this</span><span>.</span><span>strategy</span> <span>=</span> <span>strategy</span><span>;</span><span>}</span><span>public</span> <span>double</span> <span>calculateReturn</span><span>(</span><span>double</span> <span>principal</span><span>,</span> <span>double</span> <span>rate</span><span>,</span> <span>int</span> <span>years</span><span>)</span> <span>{</span><span>return</span> <span>strategy</span><span>.</span><span>calculateReturn</span><span>(</span><span>principal</span><span>,</span> <span>rate</span><span>,</span> <span>years</span><span>);</span><span>}</span><span>public</span> <span>String</span> <span>getAccountBalances</span><span>(</span><span>String</span> <span>accountId</span><span>)</span> <span>{</span><span>return</span> <span>bankServiceFacade</span><span>.</span><span>getConsolidatedBalance</span><span>(</span><span>accountId</span><span>);</span><span>}</span><span>}</span><span>package</span> <span>com.investment.service</span><span>;</span> <span>import</span> <span>com.investment.facade.BankServiceFacade</span><span>;</span> <span>import</span> <span>com.investment.strategy.InvestmentStrategy</span><span>;</span> <span>import</span> <span>org.springframework.stereotype.Service</span><span>;</span> <span>@Service</span> <span>public</span> <span>class</span> <span>InvestmentService</span> <span>{</span> <span>private</span> <span>final</span> <span>BankServiceFacade</span> <span>bankServiceFacade</span><span>;</span> <span>private</span> <span>InvestmentStrategy</span> <span>strategy</span><span>;</span> <span>public</span> <span>InvestmentService</span><span>(</span><span>BankServiceFacade</span> <span>bankServiceFacade</span><span>)</span> <span>{</span> <span>this</span><span>.</span><span>bankServiceFacade</span> <span>=</span> <span>bankServiceFacade</span><span>;</span> <span>}</span> <span>public</span> <span>void</span> <span>setStrategy</span><span>(</span><span>InvestmentStrategy</span> <span>strategy</span><span>)</span> <span>{</span> <span>this</span><span>.</span><span>strategy</span> <span>=</span> <span>strategy</span><span>;</span> <span>}</span> <span>public</span> <span>double</span> <span>calculateReturn</span><span>(</span><span>double</span> <span>principal</span><span>,</span> <span>double</span> <span>rate</span><span>,</span> <span>int</span> <span>years</span><span>)</span> <span>{</span> <span>return</span> <span>strategy</span><span>.</span><span>calculateReturn</span><span>(</span><span>principal</span><span>,</span> <span>rate</span><span>,</span> <span>years</span><span>);</span> <span>}</span> <span>public</span> <span>String</span> <span>getAccountBalances</span><span>(</span><span>String</span> <span>accountId</span><span>)</span> <span>{</span> <span>return</span> <span>bankServiceFacade</span><span>.</span><span>getConsolidatedBalance</span><span>(</span><span>accountId</span><span>);</span> <span>}</span> <span>}</span>package com.investment.service; import com.investment.facade.BankServiceFacade; import com.investment.strategy.InvestmentStrategy; import org.springframework.stereotype.Service; @Service public class InvestmentService { private final BankServiceFacade bankServiceFacade; private InvestmentStrategy strategy; public InvestmentService(BankServiceFacade bankServiceFacade) { this.bankServiceFacade = bankServiceFacade; } public void setStrategy(InvestmentStrategy strategy) { this.strategy = strategy; } public double calculateReturn(double principal, double rate, int years) { return strategy.calculateReturn(principal, rate, years); } public String getAccountBalances(String accountId) { return bankServiceFacade.getConsolidatedBalance(accountId); } }
Enter fullscreen mode Exit fullscreen mode
10. REST Controller
InvestmentController.java
<span>package</span> <span>com.investment.controller</span><span>;</span><span>import</span> <span>com.investment.service.InvestmentService</span><span>;</span><span>import</span> <span>com.investment.strategy.CompoundInterestStrategy</span><span>;</span><span>import</span> <span>com.investment.strategy.SimpleInterestStrategy</span><span>;</span><span>import</span> <span>org.springframework.web.bind.annotation.*</span><span>;</span><span>@RestController</span><span>@RequestMapping</span><span>(</span><span>"/api/investment"</span><span>)</span><span>public</span> <span>class</span> <span>InvestmentController</span> <span>{</span><span>private</span> <span>final</span> <span>InvestmentService</span> <span>investmentService</span><span>;</span><span>public</span> <span>InvestmentController</span><span>(</span><span>InvestmentService</span> <span>investmentService</span><span>)</span> <span>{</span><span>this</span><span>.</span><span>investmentService</span> <span>=</span> <span>investmentService</span><span>;</span><span>}</span><span>@GetMapping</span><span>(</span><span>"/returns"</span><span>)</span><span>public</span> <span>double</span> <span>calculateReturns</span><span>(</span><span>@RequestParam</span> <span>String</span> <span>type</span><span>,</span><span>@RequestParam</span> <span>double</span> <span>principal</span><span>,</span><span>@RequestParam</span> <span>double</span> <span>rate</span><span>,</span><span>@RequestParam</span> <span>int</span> <span>years</span><span>)</span> <span>{</span><span>if</span> <span>(</span><span>"compound"</span><span>.</span><span>equalsIgnoreCase</span><span>(</span><span>type</span><span>))</span> <span>{</span><span>investmentService</span><span>.</span><span>setStrategy</span><span>(</span><span>new</span> <span>CompoundInterestStrategy</span><span>());</span><span>}</span> <span>else</span> <span>{</span><span>investmentService</span><span>.</span><span>setStrategy</span><span>(</span><span>new</span> <span>SimpleInterestStrategy</span><span>());</span><span>}</span><span>return</span> <span>investmentService</span><span>.</span><span>calculateReturn</span><span>(</span><span>principal</span><span>,</span> <span>rate</span><span>,</span> <span>years</span><span>);</span><span>}</span><span>@GetMapping</span><span>(</span><span>"/balances"</span><span>)</span><span>public</span> <span>String</span> <span>getBalances</span><span>(</span><span>@RequestParam</span> <span>String</span> <span>accountId</span><span>)</span> <span>{</span><span>return</span> <span>investmentService</span><span>.</span><span>getAccountBalances</span><span>(</span><span>accountId</span><span>);</span><span>}</span><span>}</span><span>package</span> <span>com.investment.controller</span><span>;</span> <span>import</span> <span>com.investment.service.InvestmentService</span><span>;</span> <span>import</span> <span>com.investment.strategy.CompoundInterestStrategy</span><span>;</span> <span>import</span> <span>com.investment.strategy.SimpleInterestStrategy</span><span>;</span> <span>import</span> <span>org.springframework.web.bind.annotation.*</span><span>;</span> <span>@RestController</span> <span>@RequestMapping</span><span>(</span><span>"/api/investment"</span><span>)</span> <span>public</span> <span>class</span> <span>InvestmentController</span> <span>{</span> <span>private</span> <span>final</span> <span>InvestmentService</span> <span>investmentService</span><span>;</span> <span>public</span> <span>InvestmentController</span><span>(</span><span>InvestmentService</span> <span>investmentService</span><span>)</span> <span>{</span> <span>this</span><span>.</span><span>investmentService</span> <span>=</span> <span>investmentService</span><span>;</span> <span>}</span> <span>@GetMapping</span><span>(</span><span>"/returns"</span><span>)</span> <span>public</span> <span>double</span> <span>calculateReturns</span><span>(</span> <span>@RequestParam</span> <span>String</span> <span>type</span><span>,</span> <span>@RequestParam</span> <span>double</span> <span>principal</span><span>,</span> <span>@RequestParam</span> <span>double</span> <span>rate</span><span>,</span> <span>@RequestParam</span> <span>int</span> <span>years</span><span>)</span> <span>{</span> <span>if</span> <span>(</span><span>"compound"</span><span>.</span><span>equalsIgnoreCase</span><span>(</span><span>type</span><span>))</span> <span>{</span> <span>investmentService</span><span>.</span><span>setStrategy</span><span>(</span><span>new</span> <span>CompoundInterestStrategy</span><span>());</span> <span>}</span> <span>else</span> <span>{</span> <span>investmentService</span><span>.</span><span>setStrategy</span><span>(</span><span>new</span> <span>SimpleInterestStrategy</span><span>());</span> <span>}</span> <span>return</span> <span>investmentService</span><span>.</span><span>calculateReturn</span><span>(</span><span>principal</span><span>,</span> <span>rate</span><span>,</span> <span>years</span><span>);</span> <span>}</span> <span>@GetMapping</span><span>(</span><span>"/balances"</span><span>)</span> <span>public</span> <span>String</span> <span>getBalances</span><span>(</span><span>@RequestParam</span> <span>String</span> <span>accountId</span><span>)</span> <span>{</span> <span>return</span> <span>investmentService</span><span>.</span><span>getAccountBalances</span><span>(</span><span>accountId</span><span>);</span> <span>}</span> <span>}</span>package com.investment.controller; import com.investment.service.InvestmentService; import com.investment.strategy.CompoundInterestStrategy; import com.investment.strategy.SimpleInterestStrategy; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/investment") public class InvestmentController { private final InvestmentService investmentService; public InvestmentController(InvestmentService investmentService) { this.investmentService = investmentService; } @GetMapping("/returns") public double calculateReturns( @RequestParam String type, @RequestParam double principal, @RequestParam double rate, @RequestParam int years) { if ("compound".equalsIgnoreCase(type)) { investmentService.setStrategy(new CompoundInterestStrategy()); } else { investmentService.setStrategy(new SimpleInterestStrategy()); } return investmentService.calculateReturn(principal, rate, years); } @GetMapping("/balances") public String getBalances(@RequestParam String accountId) { return investmentService.getAccountBalances(accountId); } }
Enter fullscreen mode Exit fullscreen mode
Running the Platform
Step 1: Start MySQL
docker run <span>--name</span> mysql-investment <span>-e</span> <span>MYSQL_ROOT_PASSWORD</span><span>=</span>secret <span>-e</span> <span>MYSQL_DATABASE</span><span>=</span>investment_db <span>-p</span> 3306:3306 <span>-d</span> mysql:5.7docker run <span>--name</span> mysql-investment <span>-e</span> <span>MYSQL_ROOT_PASSWORD</span><span>=</span>secret <span>-e</span> <span>MYSQL_DATABASE</span><span>=</span>investment_db <span>-p</span> 3306:3306 <span>-d</span> mysql:5.7docker run --name mysql-investment -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=investment_db -p 3306:3306 -d mysql:5.7
Enter fullscreen mode Exit fullscreen mode
Step 2: Build and Run Spring Boot Application
./mvnw clean <span>install</span>./mvnw spring-boot:run./mvnw clean <span>install</span> ./mvnw spring-boot:run./mvnw clean install ./mvnw spring-boot:run
Enter fullscreen mode Exit fullscreen mode
Step 3: Test Endpoints
-
Calculate Returns:
http://localhost:8080/api/investment/returns?type=compound&principal=10000&rate=5&years=10
-
Get Account Balances:
http://localhost:8080/api/investment/balances?accountId=12345
Conclusion
- Scalable Architecture: Layered design with separation of concerns.
- Flexible Patterns: Easy to extend or change logic.
- Reusable Components: Adapters for multiple bank integrations.
- Efficient Design: Singleton for shared resources.
- Real-Time Updates: Observer pattern for market changes.
Read this article and more on fzeba.com.
Software Architecture Design Patterns (4 Part Series)
1 #28.1 Part 1/3 Basics of Software Architecture and Design Patterns
2 #28.2 Part 2/3 Basics of Software Architecture and Design Patterns
3 #28.3 Part 3/3 Basics of Software Architecture and Design Patterns
4 Transformig a Fintech Investment Platform: From PHP to Java (Spring Boot)
原文链接:Transformig a Fintech Investment Platform: From PHP to Java (Spring Boot)
暂无评论内容