우리는 이미 싱글톤 객체의 사용을 검토했지만 이 전략이 디자인 패턴이며 가장 많이 사용되는 패턴 중 하나라는 사실을 아직 깨닫지 못할 수도 있습니다.

실제로 이러한 패턴이 많이 있으며 특정 목적에 따라 분류할 수 있습니다.

패턴 분류

패턴 유형 애플리케이션
창작 객체 생성 문제를 해결하는 유형
구조적 아키텍처에서 정확하고 확장 가능한 클래스 계층 구조를 구축할 수 있는 패턴
행동 이 패턴 클러스터는 프로그램에서 개체 간의 안전하고 편리한 상호 작용을 촉진합니다.

일반적으로 패턴은 해결하는 문제로 특징지어집니다. Java로 작업할 때 가장 자주 접하게 되는 몇 가지 패턴을 살펴보겠습니다.

무늬 목적
하나씩 일어나는 것 우리는 이미 이 패턴에 익숙합니다. 인스턴스를 두 개 이상 가질 수 없는 클래스를 만들고 액세스하는 데 사용합니다.
반복자 우리는 또한 이것에 익숙합니다. 우리는 이 패턴을 통해 내부 표현을 드러내지 않고 컬렉션 개체를 반복할 수 있다는 것을 알고 있습니다. 컬렉션과 함께 사용됩니다.
어댑터 이 패턴은 호환되지 않는 개체를 연결하여 함께 작동할 수 있도록 합니다. 어댑터 패턴의 이름은 이것이 무엇을 하는지 정확히 상상하는 데 도움이 된다고 생각합니다. 다음은 실생활의 간단한 예입니다. 벽면 콘센트용 USB 어댑터입니다.
템플릿 방법

통합 문제를 해결하고 알고리즘의 구조를 변경하지 않고 알고리즘 단계를 변경할 수 있게 해주는 동작 프로그래밍 패턴입니다.

일련의 조립 단계 형태로 된 자동차 조립 알고리즘이 있다고 상상해보십시오.

섀시 -> 차체 -> 엔진 -> 캐빈 내부

강화된 프레임, 더 강력한 엔진 또는 추가 조명이 있는 인테리어를 넣으면 알고리즘을 변경할 필요가 없으며 추상 시퀀스는 동일하게 유지됩니다.

데코레이터 이 패턴은 개체에 유용한 기능을 제공하기 위해 개체에 대한 래퍼를 만듭니다. 이 기사의 일부로 고려할 것입니다.

Java.io에서 다음 클래스는 패턴을 구현합니다.

데코레이터 패턴

우리가 집 디자인을 위한 모델을 설명하고 있다고 상상해 봅시다.

일반적으로 접근 방식은 다음과 같습니다.

처음에는 여러 유형의 주택을 선택할 수 있습니다. 최소 구성은 지붕이 있는 1층입니다. 그런 다음 모든 종류의 데코레이터를 사용하여 자연스럽게 집 가격에 영향을 미치는 추가 매개 변수를 변경합니다.

추상 House 클래스를 만듭니다.


public abstract class House {
	String info;
 
	public String getInfo() {
    	return info;
	}
 
	public abstract int getPrice();
}
    

여기에는 2가지 방법이 있습니다.

  • getInfo()는 우리 집의 이름과 기능에 대한 정보를 반환합니다.
  • getPrice()는 현재 주택 구성의 가격을 반환합니다.

우리는 또한 벽돌과 나무로 된 표준 하우스 구현을 가지고 있습니다.


public class BrickHouse extends House {
 
	public BrickHouse() {
    	info = "Brick House";
	}
 
	@Override
	public int getPrice() {
    	return 20_000;
	}
}
 
public class WoodenHouse extends House {
 
	public WoodenHouse() {
    	info = "Wooden House";
	}
 
	@Override
	public int getPrice() {
    	return 25_000;
	}
}
    

두 클래스 모두 House 클래스를 상속하고 해당 price 메서드를 재정의하여 표준 주택에 대한 사용자 지정 가격을 설정합니다. 생성자에서 이름을 설정합니다.

다음으로 데코레이터 클래스를 작성해야 합니다. 이러한 클래스는 House 클래스 도 상속합니다 . 이를 위해 추상 데코레이터 클래스를 만듭니다.

여기에 개체를 변경하기 위한 추가 논리를 배치할 것입니다. 처음에는 추가 논리가 없으며 추상 클래스가 비어 있습니다.


abstract class HouseDecorator extends House {
}
    

다음으로 데코레이터 구현을 만듭니다. 우리는 집에 추가 기능을 추가할 수 있는 몇 가지 클래스를 만들 것입니다.


public class SecondFloor extends HouseDecorator {
	House house;
 
	public SecondFloor(House house) {
    	this.house = house;
	}
 
	@Override
	public int getPrice() {
    	return house.getPrice() + 20_000;
	}
 
	@Override
	public String getInfo() {
    	return house.getInfo() + " + second floor";
	}
}
    
우리 집에 2층을 더해주는 데코레이터

데코레이터 생성자는 "장식", 즉 수정 사항을 추가할 집을 수락합니다. 그리고 getPrice()getInfo() 메서드를 재정의하여 이전 주택을 기반으로 업데이트된 새 주택에 대한 정보를 반환합니다.


public class Garage extends HouseDecorator {
 
	House house;
	public Garage(House house) {
    	this.house = house;
	}
 
	@Override
	public int getPrice() {
    	return house.getPrice() + 5_000;
	}
 
	@Override
	public String getInfo() {
    	return house.getInfo() + " + garage";
	}
}
    
우리 집에 차고를 추가하는 데코레이터

이제 데코레이터로 집을 업데이트할 수 있습니다. 이렇게 하려면 집을 만들어야 합니다.


House brickHouse = new BrickHouse();
    

다음으로 우리는새 데코레이터와 동일한 변수, 우리 집에 전달:


brickHouse = new SecondFloor(brickHouse); 
    

우리의변수는 이제 2층이 있는 집입니다.

데코레이터와 관련된 사용 사례를 살펴보겠습니다.

예제 코드 산출

House brickHouse = new BrickHouse(); 

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());
                    

벽돌집

20000


House brickHouse = new BrickHouse(); 

  brickHouse = new SecondFloor(brickHouse); 

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());
                    

벽돌집 + 2층

40000


House brickHouse = new BrickHouse();
 

  brickHouse = new SecondFloor(brickHouse);
  brickHouse = new Garage(brickHouse);

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());
                    

벽돌집 + 2층 + 차고

45000


House woodenHouse = new SecondFloor(new Garage(new WoodenHouse())); 

  System.out.println(woodenHouse.getInfo());
  System.out.println(woodenHouse.getPrice());
                    

목조 주택 + 차고 + 2층

50000


House woodenHouse = new WoodenHouse(); 

  House woodenHouseWithGarage = new Garage(woodenHouse);

  System.out.println(woodenHouse.getInfo());
  System.out.println(woodenHouse.getPrice());

  System.out.println(woodenHouseWithGarage.getInfo());
  System.out.println(woodenHouseWithGarage.getPrice());
                    

목조 주택

25000

목조 주택 + 차고

30000

이 예제는 데코레이터를 사용하여 객체를 업그레이드하는 이점을 보여줍니다. 그래서 우리는 변경하지 않았습니다목조 주택개체 자체를 만들지 않고 대신 이전 개체를 기반으로 새 개체를 만들었습니다. 여기에서 장점에는 단점이 따른다는 것을 알 수 있습니다. 매번 메모리에 새 개체를 생성하여 메모리 소비가 증가합니다.

프로그램의 이 UML 다이어그램을 보십시오.

데코레이터는 구현이 매우 간단하고 개체를 동적으로 변경하여 업그레이드합니다. 데코레이터는 현재 클래스와 동일한 추상 유형 또는 인터페이스의 개체를 매개 변수로 사용하는 생성자에 의해 인식될 수 있습니다. Java에서 이 패턴은 I/O 클래스에서 널리 사용됩니다.

예를 들어 이미 언급했듯이 java.io.InputStream , OutputStream , ReaderWriter 의 모든 하위 클래스 에는 동일한 클래스의 개체를 허용하는 생성자가 있습니다.