객체 지향 디자인 패턴 종류
1. 싱글톤 패턴
이번엔 싱글톤 패턴에 대해서 알아보겠습니다. 🙂
싱글톤 패턴이란 인스턴스를 하나만 만들어 사용하기 위한 패턴입니다.
예를 들어 단 하나의 관리자 계정을 여러 명이서 사용하는 경우입니다.
이런 경우 어떻게 코딩하면 좋을까요?
하나의 Admin 계정을 여러 명이 공유해서 사용하는 프로그램을 짜보겠습니다.
package exSingleton;
// Admin 클래스
public class Admin {
// 정적 참조 변수
static Admin one_id;
// 객체 생성 방지
private Admin() {};
// 정적 메소드
public static Admin getInstance() {
// 참조 변수 == null일 때 객체 생성
if (one_id == null) {
one_id = new Admin();
}
// 이미 생성된 경우 return
return one_id;
}
public void Work(String s) {
System.out.println(s+" 작업을 수행했습니다.");
}
}
Admin 클래스에서 정적 참조 변수, 정적 메소드, private 생성자를 정의했습니다.
private을 생성자 앞에 붙인 이유는 객체 생성을 방지하기 위함입니다.
따라서 Admin 클래스의 정적 참조 변수는 1개만 존재합니다.
이 정적 참조 변수는 정적 메소드 getInstance()를 통해 인스턴스로 생성되고,
이미 생성된 경우는 그대로 return합니다.
아래의 Admin 계정을 받아와서 사용하는 유저들은 모두 같은 'ID'를 사용하게 되는 것이죠.
package exSingleton;
public class User {
public static void main(String[] args) {
// 생성자 앞 private으로 인해 Admin 객체를 직접 생성하려고 하면 오류가 발생합니다.
// Admin admin_user = new Admin();
// 따라서 정적 메소드를 사용해 Admin 참조변수에 인스턴스를 받아옵니다.
Admin user1 = Admin.getInstance();
Admin user2 = Admin.getInstance();
Admin user3 = Admin.getInstance();
// 참조 변수가 가리키는 인스턴스 주소 출력
System.out.println(user1);
System.out.println(user2);
System.out.println(user3);
// 하나의 Admin 인스턴스 계정으로 작업하기
user1.Work("게시물 오픈");
user2.Work("게시물 생성");
user3.Work("게시물 삭제");
}
}
user1, user2, user3은 전부 같은 메모리 주소를 참조하고 있습니다.
그리고 유일한 Admin 객체인 one_id를 getInstance()로 받아와서 Work 작업을 하는 구조입니다.
2. 프록시 패턴
저는 프록시(Proxy)라는 단어를 처음 들어봤습니다. 🙄
검색 결과 대리인이라는 뜻인데요.
프록시 패턴은 로직을 수행하는 중간에 해당 업무를 대신하는 대리자를 생성하는 패턴입니다.
그럼 프록시 패턴은 어떤 경우에 필요할까요? 🤔
대리자가 업무를 대신 해주도록 하면, 사용자가 일을 어떻게 처리하는지 모르게 할 수 있습니다.
보안과 관련된 문제를 해결하는데 유용할 것 같네요. 🙂
뿐만아니라 대리자는 어떤 업무를 하기 전에, 다른 추가 업무를 수행할 수도 있습니다.
로직의 흐름을 제어하고 다른 동작을 추가할 수도 있죠.
코드로 예시를 들어보겠습니다. 😶
은행 어플리케이션에서 고객은 자신의 계좌 잔액을 조회할 수 있습니다.
package exproxyPattern;
public interface Client {
public String getName();
public abstract float getBalance();
public abstract String getInformation(Client client);
}
package exproxyPattern;
public class NormalClient implements Client{
private String name;
private float balance;
@Override
public String getName() {
return name;
}
@Override
public float getBalance() {
return balance;
}
@Override
public String getInformation(Client client) {
return "고객님 성함은 : " + client.getName() + "잔액은 : " + client.getBalance();
}
}
여기서 끝나면 일반 고객은 getInformation() 메소드로 다른 고객들의 정보도 확인할 수 있습니다.
package exproxyPattern;
public class Bank {
public static void main(String[] args) {
NormalClient client1 = new NormalClient("루피", 5500);
NormalClient client2 = new NormalClient("초파", 3000);
// 루피가 초파의 정보 조회
System.out.println(client1.getInformation(client2));
}
}
루피가 초파의 계좌 정보를 조회할 수 있네요.
그렇게 두면 안되겠죠. 🙂 프록시 패턴을 사용해 자기 자신만 조회할 수 있도록 바꿔주겠습니다.
package exproxyPattern;
public class Proxy implements Client {
private Client client;
public Proxy (Client client) {
this.client = client;
}
@Override
public String getName() {
return client.getName();
}
@Override
public float getBalance() {
return client.getBalance();
}
@Override
public String getInformation(Client others) {
// client와 보려고하는 others 정보가 같을 때만 getInformation 메소드 호출
if (this.client.getName().equals(others.getName())) {
return this.client.getInformation(others);
}
return "다른 사람의 계좌 정보는 확인할 수 없습니다.";
}
}
package exproxyPattern;
// 은행 클래스
public class Bank {
public static void main(String[] args) {
NormalClient loopy = new NormalClient("루피", 5500);
NormalClient chopa = new NormalClient("초파", 3000);
// 루피의 대리인 생성
Proxy proxy = new Proxy(loopy);
// 대리인을 통해 초파의 정보 조회
System.out.println(proxy.getInformation(chopa));
// 대리인을 통해 자신의 정보를 조회
System.out.println(proxy.getInformation(loopy));
System.out.println(proxy.getName());
System.out.println(proxy.getBalance());
}
}
대리인(프록시)을 통한 정보 조회 시 이제 자기 자신의 정보만 조회가 가능합니다. 🙂
프록시 패턴은 권한이나 로직의 흐름을 제어하기 위해 대리자를 생성하는 패턴입니다.
3. 데코레이터 패턴
유사한 패턴으로 데코레이터 패턴이 있는데요.
프록시 패턴과 같은 방식으로 구현하면 됩니다. 😙
한 가지 차이가 있다면 리턴값에 변화를 줄 수 있다는 것입니다.
이상으로 프록시 패턴과 데코레이터 패턴에 대해 알아보았습니다. 👍
참고 자료
'객체 지향 프로그래밍 > 디자인 패턴' 카테고리의 다른 글
디자인 패턴 이해하기 (2) | 2021.03.07 |
---|---|
전략 패턴, 템플릿 콜백 패턴 (6) | 2021.01.02 |
팩토리 메서드, 템플릿 메서드 패턴 (3) | 2021.01.01 |