우리는 이미 싱글톤 객체의 사용을 검토했지만 이 전략이 디자인 패턴이며 가장 많이 사용되는 패턴 중 하나라는 사실을 아직 깨닫지 못할 수도 있습니다.
실제로 이러한 패턴이 많이 있으며 특정 목적에 따라 분류할 수 있습니다.
패턴 분류
패턴 유형 | 애플리케이션 |
---|---|
창작 | 객체 생성 문제를 해결하는 유형 |
구조적 | 아키텍처에서 정확하고 확장 가능한 클래스 계층 구조를 구축할 수 있는 패턴 |
행동 | 이 패턴 클러스터는 프로그램에서 개체 간의 안전하고 편리한 상호 작용을 촉진합니다. |
일반적으로 패턴은 해결하는 문제로 특징지어집니다. Java로 작업할 때 가장 자주 접하게 되는 몇 가지 패턴을 살펴보겠습니다.
무늬 | 목적 |
---|---|
하나씩 일어나는 것 | 우리는 이미 이 패턴에 익숙합니다. 인스턴스를 두 개 이상 가질 수 없는 클래스를 만들고 액세스하는 데 사용합니다. |
반복자 | 우리는 또한 이것에 익숙합니다. 우리는 이 패턴을 통해 내부 표현을 드러내지 않고 컬렉션 개체를 반복할 수 있다는 것을 알고 있습니다. 컬렉션과 함께 사용됩니다. |
어댑터 | 이 패턴은 호환되지 않는 개체를 연결하여 함께 작동할 수 있도록 합니다. 어댑터 패턴의 이름은 이것이 무엇을 하는지 정확히 상상하는 데 도움이 된다고 생각합니다. 다음은 실생활의 간단한 예입니다. 벽면 콘센트용 USB 어댑터입니다. |
템플릿 방법 |
통합 문제를 해결하고 알고리즘의 구조를 변경하지 않고 알고리즘 단계를 변경할 수 있게 해주는 동작 프로그래밍 패턴입니다. 일련의 조립 단계 형태로 된 자동차 조립 알고리즘이 있다고 상상해보십시오. 섀시 -> 차체 -> 엔진 -> 캐빈 내부 강화된 프레임, 더 강력한 엔진 또는 추가 조명이 있는 인테리어를 넣으면 알고리즘을 변경할 필요가 없으며 추상 시퀀스는 동일하게 유지됩니다. |
데코레이터 | 이 패턴은 개체에 유용한 기능을 제공하기 위해 개체에 대한 래퍼를 만듭니다. 이 기사의 일부로 고려할 것입니다. |
Java.io에서 다음 클래스는 패턴을 구현합니다.
무늬 | 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층이 있는 집입니다.
데코레이터와 관련된 사용 사례를 살펴보겠습니다.
예제 코드 | 산출 |
---|---|
|
벽돌집 20000 |
|
벽돌집 + 2층 40000 |
|
벽돌집 + 2층 + 차고 45000 |
|
목조 주택 + 차고 + 2층 50000 |
|
목조 주택 25000 목조 주택 + 차고 30000 |
이 예제는 데코레이터를 사용하여 객체를 업그레이드하는 이점을 보여줍니다. 그래서 우리는 변경하지 않았습니다목조 주택개체 자체를 만들지 않고 대신 이전 개체를 기반으로 새 개체를 만들었습니다. 여기에서 장점에는 단점이 따른다는 것을 알 수 있습니다. 매번 메모리에 새 개체를 생성하여 메모리 소비가 증가합니다.
프로그램의 이 UML 다이어그램을 보십시오.
데코레이터는 구현이 매우 간단하고 개체를 동적으로 변경하여 업그레이드합니다. 데코레이터는 현재 클래스와 동일한 추상 유형 또는 인터페이스의 개체를 매개 변수로 사용하는 생성자에 의해 인식될 수 있습니다. Java에서 이 패턴은 I/O 클래스에서 널리 사용됩니다.
예를 들어 이미 언급했듯이 java.io.InputStream , OutputStream , Reader 및 Writer 의 모든 하위 클래스 에는 동일한 클래스의 개체를 허용하는 생성자가 있습니다.
GO TO FULL VERSION