호환되지 않는 인터페이스를 가진 객체들이 협업할 수 있도록 하는 구조적 디자인 패턴
![스크린샷 2022-11-23 오후 9.59.11.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/80106a98-fa73-4865-9656-7fab8ffd0e12/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2022-11-23_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_9.59.11.png)
class Target {
public request(): string {
return 'Target: The default target\'s behavior.';
}
}
class Adaptee {
public specificRequest(): string {
return '.eetpadA eht fo roivaheb laicepS';
}
}
class Adapter extends Target {
private adaptee: Adaptee;
constructor(adaptee: Adaptee) {
super();
this.adaptee = adaptee;
}
public request(): string {
const result = this.adaptee.specificRequest().split('').reverse().join('');
return `Adapter: (TRANSLATED) ${result}`;
}
}
function clientCode(target: Target) {
console.log(target.request());
}
적용 할 곳
장점
단점
큰 클래스 또는 밀접하게 관련된 클래스들의 집합을 두 개의 개별 계층구조(기능/구현)로 나눈 후 각각 독립적으로 개발할 수 있도록 하는 구조 디자인 패턴
class Abstraction {
protected implementation: Implementation;
constructor(implementation: Implementation) {
this.implementation = implementation;
}
public operation(): string {
const result = this.implementation.operationImplementation();
return `Abstraction: Base operation with:\n${result}`;
}
}
class ExtendedAbstraction extends Abstraction {
public operation(): string {
const result = this.implementation.operationImplementation();
return `ExtendedAbstraction: Extended operation with:\n${result}`;
}
}
interface Implementation {
operationImplementation(): string;
}
class ConcreteImplementationA implements Implementation {
public operationImplementation(): string {
return 'ConcreteImplementationA: Here\'s the result on the platform A.';
}
}
class ConcreteImplementationB implements Implementation {
public operationImplementation(): string {
return 'ConcreteImplementationB: Here\'s the result on the platform B.';
}
}
function clientCode(abstraction: Abstraction) {
console.log(abstraction.operation());
}
let implementation = new ConcreteImplementationA();
let abstraction = new Abstraction(implementation);
clientCode(abstraction);
console.log('');
implementation = new ConcreteImplementationB();
abstraction = new ExtendedAbstraction(implementation);
clientCode(abstraction);
적용 할 곳
장점
단점
객체들을 트리 구조들로 구성한 후, 이러한 구조들과 개별 객체들처럼 작업할 수 있도록 하는 구조 패턴
abstract class Component {
protected parent!: Component | null;
public setParent(parent: Component | null) {
this.parent = parent;
}
public getParent(): Component | null {
return this.parent;
}
public add(component: Component): void { }
public remove(component: Component): void { }
public isComposite(): boolean {
return false;
}
public abstract operation(): string;
}
class Leaf extends Component {
public operation(): string {
return 'Leaf';
}
}
class Composite extends Component {
protected children: Component[] = [];
public add(component: Component): void {
this.children.push(component);
component.setParent(this);
}
public remove(component: Component): void {
const componentIndex = this.children.indexOf(component);
this.children.splice(componentIndex, 1);
component.setParent(null);
}
public isComposite(): boolean {
return true;
}
public operation(): string {
const results = [];
for (const child of this.children) {
results.push(child.operation());
}
return `Branch(${results.join('+')})`;
}
}
function clientCode(component: Component) {
console.log(`RESULT: ${component.operation()}`);
}
function clientCode2(component1: Component, component2: Component) {
// ...
if (component1.isComposite()) {
component1.add(component2);
}
console.log(`RESULT: ${component1.operation()}`);
// ...
}
const tree = new Composite();
const branch1 = new Composite();
branch1.add(new Leaf());
branch1.add(new Leaf());
const branch2 = new Composite();
branch2.add(new Leaf());
tree.add(branch1);
tree.add(branch2);
clientCode(tree);
적용 할 곳
장점
단점
객체들을 새로운 행동들을 포함한 특수 래퍼 객체들 내에 넣어서 위 행동들을 해당 객체들에 연결시키는 구조적 디자인 패턴
![스크린샷 2022-11-23 오후 11.16.07.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7f35f1e9-2a71-4634-a7f1-bfdd81a9de55/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2022-11-23_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_11.16.07.png)
interface Component {
operation(): string;
}
class ConcreteComponent implements Component {
public operation(): string {
return 'ConcreteComponent';
}
}
class Decorator implements Component {
protected component: Component;
constructor(component: Component) {
this.component = component;
}
public operation(): string {
return this.component.operation();
}
}
class ConcreteDecoratorA extends Decorator {
public operation(): string {
return `ConcreteDecoratorA(${super.operation()})`;
}
}
class ConcreteDecoratorB extends Decorator {
public operation(): string {
return `ConcreteDecoratorB(${super.operation()})`;
}
}
function clientCode(component: Component) {
// ...
console.log(`RESULT: ${component.operation()}`);
// ...
}
적용 할 곳
장점
단점
라이브러리에 대한, 프레임워크에 대한 또는 다른 클래스들의 복잡한 집합에 대한 단순화된 인터페이스를 제공하는 구조적 디자인 패턴
![스크린샷 2022-11-23 오후 10.41.52.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c16293f2-58de-443b-8478-e6e7af123666/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2022-11-23_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_10.41.52.png)
class Facade {
protected subsystem1: Subsystem1;
protected subsystem2: Subsystem2;
constructor(subsystem1?: Subsystem1, subsystem2?: Subsystem2) {
this.subsystem1 = subsystem1 || new Subsystem1();
this.subsystem2 = subsystem2 || new Subsystem2();
}
public operation(): string {
let result = 'Facade initializes subsystems:\n';
result += this.subsystem1.operation1();
result += this.subsystem2.operation1();
result += 'Facade orders subsystems to perform the action:\n';
result += this.subsystem1.operationN();
result += this.subsystem2.operationZ();
return result;
}
}
class Subsystem1 {
public operation1(): string {
return 'Subsystem1: Ready!\n';
}
// ...
public operationN(): string {
return 'Subsystem1: Go!\n';
}
}
class Subsystem2 {
public operation1(): string {
return 'Subsystem2: Get ready!\n';
}
// ...
public operationZ(): string {
return 'Subsystem2: Fire!';
}
}
function clientCode(facade: Facade) {
console.log(facade.operation());
}
적용 할 곳
장점
단점
각 객체에 모든 데이터를 유지하는 대신 여러 객체들 간에 상태의 공통 부분들을 공유하여 사용할 수 있는 RAM에 더 많은 객체들을 포함할 수 있도록 하는 구조 디자인 패턴(고유한 객체만 플라이웨이트)
![스크린샷 2022-11-25 오후 12.59.33.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ea033e54-f2c9-4b80-8084-74cdf4a71e8a/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2022-11-25_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_12.59.33.png)
class Flyweight {
private sharedState: any;
constructor(sharedState: any) {
this.sharedState = sharedState;
}
public operation(uniqueState): void {
const s = JSON.stringify(this.sharedState);
const u = JSON.stringify(uniqueState);
console.log(`Flyweight: Displaying shared (${s}) and unique (${u}) state.`);
}
}
class FlyweightFactory {
private flyweights: {[key: string]: Flyweight} = <any>{};
constructor(initialFlyweights: string[][]) {
for (const state of initialFlyweights) {
this.flyweights[this.getKey(state)] = new Flyweight(state);
}
}
private getKey(state: string[]): string {
return state.join('_');
}
public getFlyweight(sharedState: string[]): Flyweight {
const key = this.getKey(sharedState);
if (!(key in this.flyweights)) {
console.log('FlyweightFactory: Can\'t find a flyweight, creating new one.');
this.flyweights[key] = new Flyweight(sharedState);
} else {
console.log('FlyweightFactory: Reusing existing flyweight.');
}
return this.flyweights[key];
}
public listFlyweights(): void {
const count = Object.keys(this.flyweights).length;
console.log(`\nFlyweightFactory: I have ${count} flyweights:`);
for (const key in this.flyweights) {
console.log(key);
}
}
}
const factory = new FlyweightFactory([
['Chevrolet', 'Camaro2018', 'pink'],
['Mercedes Benz', 'C300', 'black'],
['Mercedes Benz', 'C500', 'red'],
['BMW', 'M5', 'red'],
['BMW', 'X6', 'white'],
// ...
]);
factory.listFlyweights();
function addCarToPoliceDatabase(
ff: FlyweightFactory, plates: string, owner: string,
brand: string, model: string, color: string,
) {
console.log('\nClient: Adding a car to database.');
const flyweight = ff.getFlyweight([brand, model, color]);
flyweight.operation([plates, owner]);
}
addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'M5', 'red');
addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'X1', 'red');
factory.listFlyweights();
적용 할 곳
장점
단점
다른 객체에 대한 대체 또는 자리표시자를 제공할 수 있는 구조 디자인 패턴
원래 객체에 대한 접근을 제어하므로, 요청이 원래 객체에 전달되기 전 또는 후에 무언가를 수행할 수 있도록 함.
어떤 객체를 사용하고자 할때, 객체를 직접적으로 참조하는 것이 아닌 해당 객체를 대항하는 객체를 통해 대상 객체에 접근하는 방식을 사용하면 해당 객체가 메모리에 존재하지 않아도 기본적인 정보를 참조하거나 설정할 수 있고, 실제 객체의 기능이 필요한 시점까지 객체의 생성을 미룰 수 있다.
![스크린샷 2022-11-24 오후 12.53.32.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/500ee6f9-ba02-432a-bdc8-e3e651e81d03/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2022-11-24_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_12.53.32.png)
interface Subject {
request(): void;
}
class RealSubject implements Subject {
public request(): void {
console.log('RealSubject: Handling request.');
}
}
class Proxy implements Subject {
private realSubject: RealSubject;
constructor(realSubject: RealSubject) {
this.realSubject = realSubject;
}
public request(): void {
if (this.checkAccess()) {
this.realSubject.request();
this.logAccess();
}
}
private checkAccess(): boolean {
console.log('Proxy: Checking access prior to firing a real request.');
return true;
}
private logAccess(): void {
console.log('Proxy: Logging the time of request.');
}
}
function clientCode(subject: Subject) {
subject.request();
}
const realSubject = new RealSubject();
clientCode(realSubject);
const proxy = new Proxy(realSubject);
clientCode(proxy);
적용 할 곳
장점
단점
참고
https://refactoring.guru/ko/design-patterns
https://velog.io/@ha0kim/Design-Pattern-구조-패턴Structural-Patterns
http://wiki.hash.kr/index.php/구조패턴
https://jhtop0419.tistory.com/109
https://koreapy.tistory.com/1127
https://en.wikipedia.org/wiki/God_object
https://velog.io/@newtownboy/디자인패턴-프록시패턴Proxy-Pattern
https://velog.io/@gmtmoney2357/디자인-패턴-프록시-패턴Proxy-Pattern-데코레이터-패턴Decorator-Pattern