Refactor Tight Coupling in VB.NET: Interfaces for Scalable Payments
The Situation
Refactor Tight Coupling in VB.NET: Interfaces for Scalable Payments

The Situation
You’re developing an online store that allows customers to make payment using payment gateways.
So you made a Class that encapsulates the payment logic, and this is what your code looks like:
Public Class OnlineStore
Public Function Checkout(
ByVal TotalAmount As Single,
ByVal Provider As String
) As String
Dim Result As String
If Provider.ToLower = "cashcash" Then
Dim objProvider As New CashCash
Result = objProvider.PayAmount(TotalAmount)
ElseIf Provider.ToLower = "mayamaya" Then
Dim objProvider As New MayaMaya
Result = objProvider.MakePayment(TotalAmount)
Else
Result = String.Format("Provider {0} not supported", Provider)
End If
Return Result
End Function
Once you have the online store class, you instantiate it from your main application like this:
Module Demo
Sub RunMain()
Dim BookStore As New OnlineStore
Dim Result As String
Console.WriteLine("{0}Tight Coupling Demo", vbNewLine)
Result = BookStore.Checkout(450.99, "cashcash")
Console.WriteLine(Result)
End Sub
End Module
It works!
You just pass the amount and the codename of the payment gateway and everything works!
Your customers can now pay using either CashCash or MayaMaya!
The Problem
Your online store class needs to know a lot more (that it needed) about the payment gateways CashCash and MayaMaya, as you can see they use different methods to perform payment (one uses PayAmount and the other uses MakePayment).
This if often referred to, as a tightly-coupled design because your class fully depends on the concrete classes CashCash and MayaMaya.
Another problem here is, obviously when you need to support new payment gateway, you’ll have to add reference to the new payment gateway and then modify your “if..then..else” routine.
The Solution
In order to solve the problems we presented (online store knowing too much of the payment gateway and not flexible enough to support new payment gateway), we have to decouple them — — and once we have done this, the result will be a loosely-coupled design.
So how do we do that?
First, we need to create an abstraction layer — — in our case, we create an Interface to define what any (and all) payment must have.
Public Interface iPaymentGatewayInterface
Function MakePayment(ByVal Amount As Single) As String
End Interface
Interface in VB.Net is one form of abstraction and is also available in older version VB6. We also prefixed the name with a small “i” to indicate that it’s an Interface (you don’t need to, but when you’re dealing with tens if not hundreds of objects, you’ll find that prefixes and other naming conventions are quite handy).
For our demo, we’ll just make one function called “MakePayment” that accepts a single parameter to hold the Amount and returns a String to represent the result of the action.
Next, we refactor (or recode) our payment gateways to make them “follow” this interface. Think of interface as a “contract” where classes that implements it must define all the functions and/or methods in that interface.
This is what the newly refactored MayaMaya code looks like:
Public Class MayaMaya
Implements iPaymentGatewayInterface
Public Function MakePayment(
ByVal Amount As Single
) As String Implements iPaymentGatewayInterface.MakePayment
Return String.Format(
"Making Payment of P{0} via {1}", Amount, Me.GetType.Name
)
End Function
End Class
Note that the function now looks exactly like that of the Interface (MakePayment) and there’s an additional element after the return type (as String), where it says “Implements …” followed by the Interface name and (abstract) Method that this class is implementing.
For the refactored CashCash, it looks almost similar to MayaMaya:
Public Class CashCash
Implements iPaymentGatewayInterface
Public Function MakePayment(
ByVal Amount As Single
) As String Implements iPaymentGatewayInterface.MakePayment
Return String.Format(
"Paying Amount of P{0} via {1}", Amount, Me.GetType.Name
)
End Function
End Class
Now that we have the Interface and refactored the payment gateways, we can refactor our online store to reflect these changes.
Here’s what the refactored online store class looks like:
Public Class OnlineStore
Public Function Checkout(
ByVal TotalAmount As Single,
ByVal Provider As iPaymentGatewayInterface
) As String
Return Provider.MakePayment(TotalAmount)
End Function
End Class
Yes, that’s the complete code of the refactored online store class :)
So what’s going on here?
The TotalAmount is still the same, but the Provider is no longer a String — — it’s now an iPaymentGatewayInterface, which means it will accept any form of payment class that implements that interface.
I hope that now, you’re seeing how this is way better :)
As for the body of the function, it just returns whatever the payment gateway returns and that’s it. We don’t have to touch this code again when we need to add new payment gateway.
Oh, how about the main application? What does it look like now?
Well, the only thing that changed is instead of passing the String for provider, we now pass a payment gateway to it — — in this example, we passed to it an instance of the MayaMaya class:
Module Demo
Sub RunMain()
Dim BookStore As New OnlineStore
Dim Result As String
Console.WriteLine("{0}Loose Coupling Demo", vbNewLine)
Result = BookStore.Checkout(450.99, New MayaMaya)
Console.WriteLine(Result)
End Sub
End Module
So, did we actually solve the 2 problems we stated?
Problem 1. Does the online store need to know too much about any payment gateway?
No. If you noticed, our online store doesn’t actually reference any payment gateway, not CashCash, not MayaMaya.
Instead, it references the abstraction or the interface — — which is one of the hallmarks of a decoupled system (not dependent on concrete classes but on abstractions).
Problem 2. Do we need to modify the “if..then..else” routine when we need to support a new payment gateway?
No. As you’ve seen, online store is now agnostic of the payment gateway — — it doesn’t know what payment gateway you pass to it, it only knows of the interface and that’s all it needs to know.
So if there’s a new payment gateway that implements the interface, we don’t change our online store logic, we just pass an instance of that new payment gateway and it just works. :)
So yeah, we solved what a tightly-coupled system inherently carries, by decoupling them using abstractions or interface.
Bonus!
When we changed the Provider from String to the Interface and we pass to it the instance of the payment class, that’s what is referred to as “dependency injection” — — which I believe I also made an article about here (just search it here) :)
There are solutions like “decoupling” or concepts like “loosely coupled” that is easier to explain when you go a step back, and explain what it’s trying to solve in the first place.
Plus, real working codes makes it faster to follow and understand as you can try them out yourselves.
Keep exploring ideas and thank you for reading my work — — have you subscribed yet? :)
See yah on the next one!
메타데이터
- post_id
- e94553d3b8f3
- slug
- from-tangled-to-tidy-refactoring-coupled-code-like-a-pro-e94553d3b8f3
- url
- https://medium.com/@pjonsms/from-tangled-to-tidy-refactoring-coupled-code-like-a-pro-e94553d3b8f3
- canonical_url
- https://medium.com/@pjonsms/from-tangled-to-tidy-refactoring-coupled-code-like-a-pro-e94553d3b8f3
- author_url
- https://medium.com/@pjonsms
- status
- ok
- fetched_at
- 2026-06-24 11:06:28