SOLID - Interface Segregation Principle
May 25, 2022 • ☕️ 5 min read • 🏷 computer, software, solid
Translated by author into: English
The “Interface Segregation Principle” (ISG) or “Interface Segregation Principle” is a principle used in software design. According to this principle, it is said that an interface should be as customized as possible and that interfaces should contain only the features used. ISG aims to increase the flexibility of the software by creating interfaces where there are no unused or unnecessary features and only the required features.
This principle is used to reduce dependencies in software design. If an interface has too many features, it can create unnecessary code complexity even where those features aren’t used. In addition, when one of these properties changes, this change can affect all classes that use the interface. To avoid these problems, the ISG says each interface should be as customized as possible and contain only the features that are needed.
The advantages of this principle include that the software is more flexible, easier to maintain and less costly to change. It is also possible that the software will become more understandable and less complex.
ISG is especially useful in large software projects. In these projects, different developers can write different modules. These modules use interfaces to communicate with each other. ISG ensures that the interfaces are small, customized and independent, allowing these modules to be developed independently of each other.
In conclusion, ISG is an important principle used in software design. This principle increases the flexibility of the software, makes it easier to maintain and reduces the cost of changes. It also makes it easy for different developers to work independently on large software projects.
An example of applying the Interface Segregation principle in PHP is as follows:
interface PaymentInterface {
public function processPayment();
public function refundPayment();
public function holdPayment();
}
class CreditCardPayment implements PaymentInterface {
public function processPayment() {
// Credit card payment processing code
}
public function refundPayment() {
// Credit card refund processing code
}
public function holdPayment() {
// Code to perform credit card payment hold transaction
}
}
class PaypalPayment implements PaymentInterface {
public function processPayment() {
// PayPal payment processing code
}
public function refundPayment() {
// PayPal refund processing code
}
public function holdPayment() {
// PayPal payment hold execution code
}
}
In the code example above, an interface named PaymentInterface is defined and this interface contains three methods named “processPayment”, “refundPayment” and “holdPayment”. Classes named CreditCardPayment and PaypalPayment can use these methods by implementing the PaymentInterface interface.
This way, the PaymentInterface contains only the three methods we need, and these methods are only used by the classes that use this interface. This means that the interface does not contain redundant methods, allowing interfaces to be designed to include customized and needed methods.
The PHP code below is an example of a class that violates the Interface Segregation principle.
interface PaymentInterface {
public function processPayment();
public function refundPayment();
public function holdPayment();
public function verifyPayment();
public function processRefund();
public function notifyUser();
}
class CreditCardPayment implements PaymentInterface {
public function processPayment() {
// Credit card payment processing code
}
public function refundPayment() {
// Credit card refund processing code
}
public function holdPayment() {
// Code to perform credit card payment hold transaction
}
public function verifyPayment() {
// Payment verification code
}
public function processRefund() {
// Refund execution code
}
public function notifyUser() {
// Code for sending notification to user
}
}
In the above example, an interface named PaymentInterface is defined and it contains six methods named “processPayment”, “refundPayment”, “holdPayment”, “verifyPayment”, “processRefund” and “notifyUser”.
However, while the CreditCardPayment class only uses the “processPayment”, “refundPayment” and “holdPayment” methods, the PaymentInterface interface includes three other methods. This means that the interface contains redundant methods, which can cause unnecessary code clutter and make it more difficult to change code for future changes.
An example to implement the Interface Segregation principle in GoLang is as follows:
package main
import "fmt"
type Payment interface {
processPayment()
refundPayment()
holdPayment()
}
type CreditCardPayment struct{}
func (cc *CreditCardPayment) processPayment() {
fmt.Println("Credit card payment processing code")
}
func (cc *CreditCardPayment) refundPayment() {
fmt.Println("Credit card refund processing code")
}
func (cc *CreditCardPayment) holdPayment() {
fmt.Println("Code to perform credit card payment hold transaction")
}
type PaypalPayment struct{}
func (pp *PaypalPayment) processPayment() {
fmt.Println("PayPal payment processing code")
}
func (pp *PaypalPayment) refundPayment() {
fmt.Println("PayPal refund processing code")
}
func (pp *PaypalPayment) holdPayment() {
fmt.Println("PayPal payment hold execution code")
}
In the above example an interface named Payment is defined and this interface contains three methods named “processPayment”, “refundPayment” and “holdPayment”. Classes named CreditCardPayment and PaypalPayment can use these methods by implementing the Payment interface.
This way the Payment interface contains only the three methods we need, and these methods are only used by the classes that use that interface. This means that the interface does not contain redundant methods, allowing interfaces to be designed to include customized and needed methods.
Similar to the PHP example, the GoLang code below is an example that violates the Interface Segregation principle.
package main
import "fmt"
type Payment interface {
processPayment()
refundPayment()
holdPayment()
verifyPayment()
processRefund()
notifyUser()
}
type CreditCardPayment struct{}
func (cc *CreditCardPayment) processPayment() {
fmt.Println("Credit card payment processing code")
}
func (cc *CreditCardPayment) refundPayment() {
fmt.Println("Credit card refund processing code")
}
func (cc *CreditCardPayment) holdPayment() {
fmt.Println("Code to perform credit card payment hold transaction")
}
func (cc *CreditCardPayment) verifyPayment() {
fmt.Println("Payment verification code")
}
func (cc *CreditCardPayment) processRefund() {
fmt.Println("Refund execution code")
}
func (cc *CreditCardPayment) notifyUser() {
fmt.Println("Code for sending notification to user")
}
In the above example, an interface named Payment is defined and this interface includes six methods named “processPayment”, “refundPayment”, “holdPayment”, “verifyPayment”, “processRefund” and “notifyUser”.
However, while the CreditCardPayment class only uses the “processPayment”, “refundPayment” and “holdPayment” methods, the Payment interface includes the other three methods. This means that the interface contains redundant methods and this can cause unnecessary code mess and make code change more difficult for future changes.
Resources
- https://en.wikipedia.org/wiki/Interface_segregation_principle#:~:text=In%20the%20field%20of%20software,are%20of%20interest%20to%20them.
- https://www.tutorialsteacher.com/csharp/interface-segregation-principle
- https://www.oodesign.com/interface-segregation-principle