Liskov Substitution Principle (LSP)
Tags: go, solidprinciples
Published: 2023-09-08 04:31:28

Robert C. Martin menjelaskan:
> Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

Dave Cheney menjelaskan:
> The Liskov Substitution Principle encourages you to express the dependencies between your packages in terms of interfaces, not concrete types. By defining small interfaces, we can be more confident that implementations will faithfully satisfy their contract.

Karena pada golang tidak ada konsep inheritance, maka LSP bisa dicapai dengan menggunakan interface.

Agar lebih jelasnya, perhatikan kode yang ada pada contoh OCP sebelumnya:

```go
package main

import (
	"fmt"
)

// User adalah tipe data yang mewakili informasi pengguna.
type User struct {
	ID       int
	Username string
	Email    string
}

type UserRepository interface {
	GetUserByUsername(username string) (User, error)
	Save() error
}

// UserRepository bertanggung jawab untuk berinteraksi dengan basis data pengguna.
type UserMySQLRepository struct{}

func (r *UserMySQLRepository) GetUserByUsername(username string) (User, error) {
	// Logika untuk mengambil pengguna berdasarkan username
	return User{}, nil
}

func (r *UserMySQLRepository) Save() error {
	// Logika untuk menyimpan ke basis data
	return nil
}

type UserOracleRepository struct{}

func (r *UserOracleRepository) GetUserByUsername(username string) (User, error) {
	// Logika untuk mengambil pengguna berdasarkan username
	return User{}, nil
}

func (r *UserOracleRepository) Save() error {
	// Logika untuk menyimpan ke basis data
	return nil
}


// UserValidator bertanggung jawab untuk memvalidasi data pengguna.
type UserValidator struct{}

func (uv *UserValidator) Validate() error {
	// Logika validasi pengguna seperti validasi email, kata sandi, dsb.
	return nil
}

// UserService adalah layanan yang berfungsi sebagai penghubung antara klien dan data pengguna.
type UserService struct {
	Repository UserRepository
	Validator  UserValidator
}

// CreateUser membuat pengguna baru dengan menggunakan Repository dan Validator.
func (us *UserService) CreateUser(user User) error {
	// Validasi pengguna menggunakan Validator
	if err := us.Validator.Validate(); err != nil {
		return err
	}

	// Simpan pengguna ke basis data menggunakan Repository
	if err := us.Repository.Save(); err != nil {
		return err
	}

	return nil
}

// GetUserByID mengambil pengguna berdasarkan ID dari Repository.
func (us *UserService) GetUserByUsername(username string) (User, error) {
	return us.Repository.GetUserByUsername(username)
}

func main() {
	// Inisialisasi layanan pengguna
	userService := UserService{
		Repository: &UserOracleRepository{}, // Contoh sederhana, seharusnya menggunakan koneksi basis data nyata.
		Validator:  UserValidator{},        // Contoh sederhana, seharusnya ada validasi yang lebih lengkap.
	}

	// Membuat pengguna baru
	newUser := User{ID: 1, Username: "john_doe", Email: "john@example.com"}
	err := userService.CreateUser(newUser)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	// Mengambil pengguna berdasarkan username
	user, err := userService.GetUserByUsername("myUser")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("User:", user)
}
```

Kode ini sudah menerapkan LSP, karena struct `UserOracleRepository` dan `UserMySQLRepository` dapat digunakan pada `UserService`. 


## Referensi
- https://dave.cheney.net/2016/08/20/solid-go-design
- https://faun.dev/c/stories/josueparra2892/golang-solid-principles/
- https://web.archive.org/web/20150905081111/http://www.objectmentor.com/resources/articles/lsp.pdf