Facade Pattern
프로그램이라는 것은 점점 커지는 경향이 있음
많은 클래스가 만들어져 서로 관계를 맺으면서 복잡하게 됨
상호 관련된 많은 클래스를 적절하게 제어해야 함
그 처리를 실행하기 위한 창구 역할을 하는 별도의 인터페이스를 두는 것
Facade 는 건물의 앞면을 의미한다
-> Facade Pattern 이란 건물의 앞면처럼 그 뒤쪽의 복잡함은 내부에 숨기고 간단한 인터페이스만 제공
Client는 여러 라이브러리와 클래스를 필요로 하는 상태
이런 경우 여러 클래스나 라이브러리를 조합해서 더 간단한 인터페이스를 제공해주는 클래스를 생각해볼 수 있음.
->
Client는 복잡한 클래스와 라이브러리 상대할 필요없이 간단한 인터페이스만 제공하는 Facade Pattern 사용해서 더 쉽게 개발
우주로켓을 만들기 위해 stage1 stage2 capsule이 있음
우주선 목적지까지 보낼 때 복잡한 과정 필요
stage1 : 점화, 이륙, 분리
stage2 : 점화, 분리
capsule : 점화, 착률의 과정 필요
->
이러한 과정 매번 Client가 다루기 번거롭기 때문에 하나로 묶은 Facade Pattern 만들면 개발하기 쉬움.
Facade Pattern for Deep Learning Framework
딥러닝에 적용시켜본 Facade Pattern을 알아보자.
데이터셋의 이름 : Fashion MNIST
- 70000개의 28x28픽셀의 이미지들과 10개의 클래스 정답으로 구성된 데이터 셋
- 훈련데이터 60000개, 테스트데이터 10000개
이미지를 input으로 하면 딥러닝을 거쳐
ouput으로 라벨(정답)이 나올것이다. 실행화면은 다음과 같다.
Facade Pattern in Application : 절차지향적 코드
# #========================절차지향적 프로그램
import tensorflow as tf
import matplotlib.pyplot as plt
fashion_mnist = tf.keras.datasets.fashion_mnist
(train_X, train_Y), (test_X, test_Y) = fashion_mnist.load_data()
print(len(train_X), len(test_X))
plt.imshow(train_X[0], cmap='gray')
plt.colorbar()
plt.show()
print(train_Y[0])
train_X = train_X / 255.0
test_X = test_X /255.0
train_X = train_X.reshape(-1, 28, 28, 1)
test_X = test_X.reshape(-1, 28, 28, 1)
print(train_X.shape, test_X.shape)
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(input_shape=(28,28,1), kernel_size=(3, 3), filters = 16),
tf.keras.layers.Conv2D(kernel_size=(3, 3), filters=32),
tf.keras.layers.Conv2D(kernel_size=(3, 3), filters=64),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(units=128, activation='relu'),
tf.keras.layers.Dense(units=10, activation='softmax')
])
model.compile(optimizer=tf.keras.optimizers.Adam(),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
model.summary()
history = model.fit(train_X, train_Y, epochs=25, validation_split=0.25)
Facade Pattern in Application : 객체지향적 코드
#========================객체지향적 Facade 응용
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
class DataProcess:
def __init__(self):
self.train_X = 0
self.train_Y = 0
self.test_X = 0
self.test_Y = 0
self.N = 0
self.dimX = 0
self.dimY = 0
def setImageDim(self):
self.N = len(self.train_X)
imageCase = self.train_X[0]
self.dimY = imageCase.shape[0]
self.dimX = imageCase.shape[1]
def readDataset(self):
fashion_mnist = tf.keras.datasets.fashion_mnist
(self.train_X, self.train_Y), (self.test_X, self.test_Y) = fashion_mnist.load_data()
self.setImageDim()
def normalize(self):
# 0~1 normalize
self.train_X = self.train_X / 255.0
self.test_X = self.test_X /255.0
def trainReady(self):
#reshape the image dimension to (#, 28, 28, 1)
self.train_X = self.train_X.reshape(-1, self.dimY, self.dimX, 1)
self.test_X = self.test_X.reshape(-1, self.dimY, self.dimX, 1)
def showStatus(self):
print("DP: 총", self.N, "장의 이미지가 로드되었습니다.")
print("DP: 각 이미지 크기는 ", self.dimY, "X", self.dimX, "입니다.")
class DeepLearning:
def __init__(self):
self.model = tf.keras.Sequential()
self.optimizer = tf.keras.optimizers.Adam()
self.data_X = 0
self.data_Y = 0
self.epoch = 0
self.validation_split = 0
def setEpoch(self, epoch):
self.epoch = epoch
return self
def setValidSplitRatio(self, split_ratio):
self.validation_split = split_ratio
return self
def setInputData(self, X, Y):
self.data_X = X
self.data_Y = Y
return self
def setLayers(self):
self.model.add(tf.keras.layers.Conv2D(input_shape=(28,28,1), kernel_size=(3, 3), filters = 16))
self.model.add(tf.keras.layers.Conv2D(kernel_size=(3, 3), filters=32))
self.model.add(tf.keras.layers.Conv2D(kernel_size=(3, 3), filters=64))
self.model.add(tf.keras.layers.Flatten())
self.model.add(tf.keras.layers.Dense(units=128, activation='relu'))
self.model.add(tf.keras.layers.Dense(units=10, activation='softmax'))
def compileDL(self):
self.model.compile(optimizer=self.optimizer,
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
def showModelSummary(self):
self.model.summary()
def goTrain(self):
print("DL: 학습을 시작합니다.")
history = self.model.fit(self.data_X, self.data_Y, epochs=self.epoch, validation_split=self.validation_split)
class Visualize:
def __init__(self):
pass
def showImage(self, image):
print("VS: 이미지를 출력합니다.")
plt.imshow(image, cmap='gray')
plt.colorbar()
plt.show()
#FACADE
class Learning:
def __init__(self):
self.DP = DataProcess()
self.VS = Visualize()
self.DL = DeepLearning()
def learn(self):
self.DP.readDataset()
self.VS.showImage(self.DP.train_X[0])
self.DP.normalize()
self.DP.trainReady()
self.DP.showStatus()
self.DL.setInputData(self.DP.train_X, self.DP.train_Y).setEpoch(25).setValidSplitRatio(0.2)
self.DL.setLayers()
self.DL.compileDL()
self.DL.goTrain()
#======================main
learn = Learning()
learn.learn()
Facade 의 역할은 무엇인가?
Facade는 복잡한 것을 단순하게 보여줌
핵심은 인터페이스를 적게하는 일
- 클래스나 메소드가 많이 보이면, 프로그래머는 무엇을 사용하면 좋을지 망설이게 되고, 호출하는 순서에도 주의 해야만 한다. -> 주의해야한다는 것은 틀리기 쉽다는 것
재귀적 Facade 패턴의 적용
가령 Facade 역할을 하는 클래스의 집합이 여러개가 있다고 가정.
이때 클래스의 집합을 정리해서 새로운 Facade 역할을 도입할 수 있다.
즉, Facade 패턴을 재귀적으로 적용하는 것이다
상당히 큰 시스템이 다수의 클래스, 다수의 패키지를 포함하고 있을 때. 요소들에 Facade 패턴을 적용하면 시스템은 보다 편리하게 된다.