[cs] - 싱글톤 패턴, 브릿지 패턴, 전략 패턴

링딩·2023년 4월 23일
0

Computer Science

목록 보기
38/49


1. 싱글톤 패턴이란?

  • 정의
    어플리케이션이 시작될 때 어떤 클래스가 최초 한번만 메모리를 할당하고(static) 그 메모리에 인스턴스를 만들어 사용하는 디자인 패턴

예를 들면 이런 곳에서 쓰면... 좋겠지?

  • 레지스트리 같은 설정 파일에서 객체가 여러개 생성된다면 설정 값이 변경될 위험이 생길 수 있다.

이때 인스턴스가 1개만 생성되는 특징인 '싱글톤 패턴'을 이용시 하나의 인스턴스를 메모리에 등록해서 여러 쓰레드가 동시에 해당 인스턴스를 공유하여 사용할 수 있게끔 할 수 있기 때문에
=> 요청이 많은 곳에서 사용하면 효율을 높일 수 있다.

🤔but 주의: 동시성 문제를 고려해서 설계해야 된다.


장점

  1. 고정된 메모리 영역을 얻으면서 한 번의 new로 인스턴스를 사용함
    -> 메모리 낭비 방지
  2. 싱글톤으로 만들어진 클래스의 인스턴스는 전역이다.
    -> 다른 클래스의 인스턴스들이 데이터를 공유하기 쉬움.
  3. 두 번째 이용시부터는 객체 로딩시간이 줄어든다.
    => 성능향상
  4. 인스턴스가 절대적으로 한 개만 존재하는 것을 보증하고 싶을 경우 이용

이럴 때 사용...

이런 장점을 통해 DBCP(DataBaseCommection Pool)이라는 공통된 객체를 여러개 생성해서 사용해야 하는 상황에서 주로 쓰인다.


단점

싱글톤 인스턴스가 너무 많은 일을 하거나 혹은 많은 데이터를 공유할 경우 다른 클래스의 인스턴트들 간의 결합도가 높아져 "개방-폐쇄 원칙"을 위배 하게 된다.
=> 이로인해 수정이 어려워지고 유지보수 비용이 높아질 수 있다.

싱글톤 패턴은 지향해야 하는가?

  • 멀티쓰레드 환경에서 동기화 처리를 하지 않을 경우 인스턴스가 2개가 생성될 수도 있다.
    => 꼭 필요한 경우에만 사용하자 그렇기 때문에 그렇지 않은 곳에서는 지양하자



1-2. 싱글톤 패턴의 예제

  • 자신을 멤버로 선언해서 메모리에 올려놓는다. (static)

  • 외부에서 멤버로 선언된 car를 가져올 수 있는 메소드를 만들어 getInstance 메서드 외에는 CarClass 객체를 생성 하거나 사용할 수 없게 된다.
    -> 해당 차 객체를 누군가 이용한다면 이용을 못한다.(싱글톤 패턴의 예시)





2. 브릿지 패턴이란?

  • 브리지 패턴은 기능을 처리하는 클래스구현을 담당하는 추상 클래스로 구별
    -> 구현뿐 아니라 추상화도 독립적 변경이 필요할 때 브리지 패턴을 사용한다
    => 2개의 객체는 추상화를 구현에서 분리하여 매우 독립적으로 사용할 수 있다
  • 브리지 패턴은 새로운 인터페이스를 정의하여 기존 프로그램의 변경 없이 기능을 확장할 수 있음.

🤔 이런 때에 사용하자.

  1. 기존 시스템에 부수적인 새로운 기능들을 지속적으로 추가할 때
  2. 부모 추상 클래스가 기본 규칙 세트를 정의하고 구체적인 클래스가 추가 규칙을 추가하고 싶은 경우
  3. 객체에 대한 참조가 있는 추상 클래스가 있고 각 구체적인 클래스에서 정의될 추상 메서드가 있는 경우



장점

  • 클래스 계청을 분리할 때 완전한 인터페이스를 결합하지 않는다. 이를 통해 클래스에서 구현과 추상 부분 2개의 계층으로 분리할 수 있고, 분리된 2개의 추상 계층과 구현 계층은 독립적인 확장이 가능하다.
  • 브리지 패턴을 사용하면 런타임 시점에 어떤 방식으로 기능을 구현할지 선택할 수 있다.
  • 기능을 독립적으로 확장할 수 있다면 상세한 기능을 외부로부터 숨길 수 있는 은닉 효과도 얻을 수 있다.

단점

  • 추상화를 통해 코드를 분리할 경우 코드 디자인 설계가 복잡해진다





전략 패턴이란?

◽ 특정 컨텍스트에서 알고리즘을 별도로 분리하는 설계 방법을 의미

특정한 기능을 수행하는데에 있어 다양한 알고리즘이 적용될 수 있는 경우, 이 다양한 알고리즘을 별도로 분리하는 설계 방법을 의미


예를 들면...

한 과일 매장은 상황에 따라 다른 가격 할인 정책을 적용하고 있다. 제일 먼저 온 손님에게 10%를 할인해주고 마지막 손님은 20% 그리고 신선도가 떨어진 과일에 대해서는 20% 할인을 해주고 있다.

만일 전략패턴이 적용되지 않는다면?

이렇게 되면 할인조건에 따라서 if-else로 조건 및 분기를 달게 될 것이다... 그렇게 되면 아래와 같은 문제점이 발생할 수 있다.

  1. 새로운 가격정책이 추가되었을 때 기존의 코드를 복사 붙여넣기 방식으로 추가해야 합니다.
    -> 현재로써는 간단해 보이나 이후에 복잡한 로직으로 형성될 경우 이것은 유지보수에 안좋다.
  2. 계산 로직의 변경이 된다면 연쇄적으로 수정될 가능성이 높아진다.
  3. 시간이 지날수록 코드 분석이 어려워진다.

전략패턴이 적용된다면?

  1. 할인이라는 알고리즘을 DiscountPolicy 라는 인터페이스를 통해 분리하여 관리할 것이다.
   public interface DiscountPolicy {
    	double calculateWithDisCountRate(Item item);
    }
    
    public class FirstCustomerDiscount implements DiscountPolicy{
    	@Override
    	public double calculateWithDisCountRate(Item item) {
    		return item.getPrice() * 0.9;
    	}
    }
    
    public class LastCustomerDiscount implements DiscountPolicy{
    	@Override
    	public double calculateWithDisCountRate(Item item) {
    		return item.getPrice() * 0.8;
    	}
    }
    
    public class UnFreshFruitDiscount implements DiscountPolicy{
    	@Override
    	public double calculateWithDisCountRate(Item item) {
    		return item.getPrice() * 0.8;
    	}
    }

  1. 이를 기존의 Calculator 클래스에서 생성자를 통해 필요한 하위 타입을 주입받아 사용
   
    	private final DiscountPolicy discountPolicy;
    
    	public Calculator(DiscountPolicy discountPolicy) {
    		this.discountPolicy = discountPolicy;
    	}
    
    	public double calculate(List<Item> items) {
    		double sum = 0;
    		for (Item item : items) {
    			sum += discountPolicy.calculateWithDisCountRate(item);
    		}
    		return sum;
    	}
    }

적용된 코드를 통해

  • 외부에서 특정 경우(첫번째 손님, 마지막 손님, 싱싱하지 않은 과일)에 대한 할인정책을 생성자를 통해 전달해줄 수 있다.
 public class FruitController {
    	public static void main(String[] args) {
    		Calculator calculator = new Calculator(new FirstCustomerDiscount());
    		calculator.calculate(Arrays.asList(
    			new Item("Apple", 3000),
    			new Item("Banana", 3000),
    			new Item("Orange", 2000),
    			new Item("Pitch", 4000)
    		));
    	}
    }

이것은 첫번째 손님 할인정책을 적용한 코드의 예시

일반적으로 Controller는 사용자의 요청(클릭이나 입력) 등을 매핑하여 받아오기 때문에 특정 알고리즘(첫번째 손님 계산)을 눌렀다는 것을 알 수 있다. (전략패턴)

장점

  • 컨텍스트 코드의 변경 없이(기존 코드 변경 없이) 새로운 전략을 추가할 수 있다
  • 새로운 전략에 대해서는 새로운 클래스를 통해 관리하기 때문에 OCP의 원칙을 준수할 수 있는 패턴

단점

모든 상황에서 전략패턴이 사용되는 것은 유용하지 않다.

  • 컨텍스트에 적용되는 알고리즘이 하나이거나 두개인 경우는 분기를 타는 것이 편한 경우도 존재한다.
    -> 그러나 요구사항의 변경으로 변경될 여지가 있고 변화의 형태가 다양함이 어느정도 보장될 때 전략패턴을 고려해보시길 추천드립니다.

출처

devmoony님의 글을 바탕으로 작성하였습니다.

hirlawldo님의 글을 바탕으로 작성하였습니다.

kyle님의 글을 바탕으로 작성하였습니다.

profile
초짜 백엔드 개린이

0개의 댓글