author-pic

Ferry S

An ISTJ, Type 5, Engineer, Gamer, and Thriller-Movies-Lover
Contoh Facade Design Pattern
Sunday Aug 29th, 2021 07:39 pm5 mins read
Java, Design Pattern, Tips & Tutorial
Contoh Facade Design Pattern
Source: dbse-teaching.github.io - System Design

Kali ini gw membahas tentang Facade Design Pattern. Sebenarnya penggunaan design ini cukup umum sih. Gw rasa beberapa diantara kita udah familiar dengan Facade ketika membuat sebuah API. Bagi yang menerapkan Clean Architecture gw rasa udah sering menggunakan design pattern ini ketika membuat gateway. Tingkat kompleksitasnya juga cukup rendah, cukup mudah diimplementasikan.

Facade Design Pattern adalah Structural Design Pattern yang menyederhanakan sistem, library, atau framework yang complex ke dalam sebuah interface yang simple digunakan.

Design Pattern

Use Case

Kita akan membuat sebuah system untuk melakukan pembuatan user dan penghapusan user dari database berdasarkan request yang diberikan.

  • Ketika menambahkan user baru, kita dapat menambahkannya berdasarkan request yang diberikan;
  • Setelah sukses kita akan mendapatkan id dari user yang disimpan tadi;
  • Lalu dari user id tersebut, kita juga akan menambahkan user address berdasarkan address dari request dan user id tadi;
  • Ketika menghapus user, kita perlu mengecek apakah user id tersebut digunakan oleh user dan user address;
  • Jika ada, maka user dan user address akan dihapus berdasarkan user id yang dikirimkan dari request;

Contoh Code

UserRequest Class

public class UserRequest{
	private final String userName;
	private final String address;

	public UserRequest(String userName, String address){
		this.userName = userName;
		this.address = address;
	}

	public String getUserName(){
		return userName;
	}

	public String getAddress(){
		return address;
	}
}

UserRepository Interface

public interface UserRepository{
	int createUser(UserEntity userEntity);
	UserEntity getUserById(int id);
	void deleteUser(int id);
}

UserRepositoryImpl Class

public class UserRepositoryImpl implements UserRepository{
	@Override
	public int createUser(UserEntity userEntity){
		System.out.println("success create user");
		return 1;
	}

	@Override
	public UserEntity getUserById(int id){
		System.out.println("getting user by id");
		return new UserEntity();
	}

	@Override
	public void deleteUser(int id){
		System.out.println("success delete user by id");
	}
}

UserAddressRepository Interface

public interface UserAddressRepository{
	int createUserAddress(UserAddressEntity userAddressEntity);
	UserAddressEntity getUserAddressById(int id);
	void deleteUserAddress(int id);
}

UserAddressRepositoryImpl Class

public class UserAddressRepositoryImpl implements UserAddressRepository{
	@Override
	public int createUserAddress(UserAddressEntity userAddressEntity){
		System.out.println("success create user address");
		return 1;
	}

	@Override
	public UserAddressEntity getUserAddressById(int id){
		System.out.println("getting user address by id");
		return new UserAddressEntity();
	}

	@Override
	public void deleteUserAddress(int id){
		System.out.println("success delete user address by id");
	}
}

UserEntity Class

public class UserEntity{
	private int userId;
	private String userName;

	public int getUserId(){
		return userId;
	}

	public void setUserId(int userId){
		this.userId = userId;
	}

	public String getUserName(){
		return userName;
	}

	public void setUserName(String userName){
		this.userName = userName;
	}
}

UserAddressEntity Class

public class UserAddressEntity{
	private int userId;
	private String address;

	public int getUserId(){
		return userId;
	}

	public void setUserId(int userId){
		this.userId = userId;
	}

	public String getAddress(){
		return address;
	}

	public void setAddress(String address){
		this.address = address;
	}
}

Contoh Penggunaan

public static void main(String[] args){
	UserRepositoryImpl userRepository = new UserRepositoryImpl();
	UserAddressRepositoryImpl userAddressRepository = new UserAddressRepositoryImpl();

	//create user
	UserRequest userRequest = new UserRequest("ferry", "solok");
	UserEntity userEntity = new UserEntity();
	userEntity.setUserName(userRequest.getUserName());
	int user = userRepository.createUser(userEntity);
	UserAddressEntity userAddressEntity = new UserAddressEntity();
	userAddressEntity.setUserId(user);
	userAddressEntity.setAddress(userRequest.getAddress());
	userAddressRepository.createUserAddress(userAddressEntity);

	//delete user
	int userId = 1;
	UserAddressEntity userAddressById = userAddressRepository.getUserAddressById(userId);
	if(userAddressById != null){
		userAddressRepository.deleteUserAddress(userId);
	}
	UserEntity userById = userRepository.getUserById(userId);
	if(userById != null){
		userRepository.deleteUser(userId);
	}
}

Kita sudah mengimplementasi requirement di atas. Implementasinya ditulis di dalam client code.

Masalah

Disini client sendiri yang melakukan eksekusi perintah sesuai requirement di atas. Itu semua terlalu complex dilakukan di dalam client code. Sehingga ketika terjadi perubahan, atau penambahan logic, semua client code harus di-refactor.

Solusi

Selanjutnya kita coba buat menggunakan Facade Design Pattern😎.

UserService Interface

public interface UserService{
	void createUser(UserRequest userRequest);
	void deleteUser(int id);
}

UserServiceImpl Class

public class UserServiceImpl implements UserService{
	private final UserRepository userRepository;
	private final UserAddressRepository userAddressRepository;

	public UserServiceImpl(UserRepository userRepository, UserAddressRepository userAddressRepository){
		this.userRepository = userRepository;
		this.userAddressRepository = userAddressRepository;
	}

	@Override
	public void createUser(UserRequest userRequest){
		UserEntity userEntity = new UserEntity();
		userEntity.setUserName(userRequest.getUserName());
		int user = userRepository.createUser(userEntity);
		UserAddressEntity userAddressEntity = new UserAddressEntity();
		userAddressEntity.setUserId(user);
		userAddressEntity.setAddress(userRequest.getAddress());
		userAddressRepository.createUserAddress(userAddressEntity);
	}

	@Override
	public void deleteUser(int id){
		UserAddressEntity userAddressById = userAddressRepository.getUserAddressById(id);
		if(userAddressById != null){
			userAddressRepository.deleteUserAddress(id);
		}
		UserEntity userById = userRepository.getUserById(id);
		if(userById != null){
			userRepository.deleteUser(id);
		}
	}
}

Contoh Penggunaan

public static void main(String[] args){
	//create user
	UserRequest userRequest = new UserRequest("ferry", "solok");
	UserService userService = new UserServiceImpl(new UserRepositoryImpl(), new UserAddressRepositoryImpl());
	userService.createUser(userRequest);

	//delete user
	int userId = 1;
	userService.deleteUser(userId);
}

Selain penambahan dua class di atas, kita tidak perlu melakukan perubahan di class lainnya. Sekarang client code hanya tinggal melakukan inisialisasi object UserService dan tinggal execute method createUser() untuk penambahan user dan deleteUser() untuk penghapusan user. Client tidak perlu repot-repot bikin atau tau kompleksitas logic dari algoritma tersebut.

Kenapa menggunakan Facade Design Pattern?

Facade Design Pattern cocok digunakan jika ingin mengurangi kompleksitas subsystem menjadi lebih straightforward. Sangat wajar subsystem akan terus menjadi kompleks, oleh karena itu kita butuh interface yang menyederhanakan itu. Tapi jika objeknya terlalu besar, Facade juga bisa menjadi God Object, karena terlalu banyak complexitas yang di-handle di dalamnya. Untuk itu maka perlu dibuat kembali Facade baru yang lebih sederhana dan memiliki kohesi yang tinggi dari Facade sebelumnya.

Verdict

Penerapannya cukup simple dan gampang dipahami. Intinya tujuan Facade Design Pattern ini adalah untuk menyederhanakan sebuah logic yang complex ke dalam sebuah class yang lebih straightforward. Sehingga client yang menggunakan ga perlu tahu detail kompleksitas logic di dalamnya.