author-pic

Ferry S

An ISTJ, Type 5, Engineer, Gamer, and Thriller-Movies-Lover
Contoh Façade Design Pattern
Sun. Aug 29th, 2021 07:39 PM5 mins read
Contoh Façade Design Pattern
Source: flickr@Alain Rouiller - façades avec faïences 2

Kali ini gw membahas tentang Façade 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.

Façade Design Pattern adalah Structural Design Pattern yang menyederhanakan sistem, library, atau framework yang kompleks ke dalam sebuah interface yang mudah digunakan.

Design Pattern

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;

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.

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.

Selanjutnya kita coba buat menggunakan Façade Design Pattern😎.

UserService Interface

public interface UserService{
	void createUser(UserRequest userRequest);
	void deleteUser(int id);
	void createAddress(UserRequest userRequest, int userId);
	void deleteAddress(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);
		createAddress(userRequest, user);
	}

	@Override
	public void createAddress(UserRequest userRequest, int userId){
		UserAddressEntity userAddressEntity = new UserAddressEntity();
		userAddressEntity.setUserId(userId);
		userAddressEntity.setAddress(userRequest.getAddress());
		userAddressRepository.createUserAddress(userAddressEntity);
	}

	@Override
	public void deleteUser(int id){
		deleteAddress(id);
		UserEntity userById = userRepository.getUserById(id);
		if(userById != null){
			userRepository.deleteUser(id);
		}
	}

	@Override
	public void deleteAddress(int id){
		UserAddressEntity userAddressById = userAddressRepository.getUserAddressById(id);
		if(userAddressById != null){
			userAddressRepository.deleteUserAddress(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 membuat object UserService dan execute method createUser() dan deleteUser(). Kalau mau membuat atau menghapus addressnya saja juga bisa. Tidak perlu repot-repot bikin lagi atau tau kompleksitas algoritmanya.

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

Penerapannya cukup simple dan gampang dipahami. Intinya tujuan Façade 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.