
Decorater 패턴
객체의 결합을 통해 기능을 동적으로 유연하게 확장 할 수 있게 해주는 패턴

장점
단점
package main
import (
"fmt"
"github.com/tuckersGo/goWeb/web9/cipher"
"github.com/tuckersGo/goWeb/web9/lzw"
)
type Component interface {
Operator(string)
}
var sentData string
// 최종 결과 값
// 실제 기본기능을 가짐
type SendComponent struct{}
// 데이터를 보낸다.
func (self *SendComponent) Operator(data string) {
sentData = data
}
// 압축하는 컴포넌트
type ZipComponent struct {
com Component //기본 기능
}
// 압축 해주는 기능
func (self *ZipComponent) Operator(data string) {
zipData, err := lzw.Write([]byte(data))
// 터커의 압축 패키지
if err != nil {
panic(err) // 에러가 있을 시 프로그램 종료
}
self.com.Operator(string(zipData))
//압축된 데이터가 샌드 컴포넌트의 오퍼레이터로
}
// 암호화 하는 컴포넌트
type EncryptComponent struct {
key string // 암호화를 위한 키
com Component //기본 기능
}
// 암호화 해주는 기능
func (self *EncryptComponent) Operator(data string) {
encryptData, err := cipher.Encrypt([]byte(data), self.key)
// 터커의 암호화 패키지
if err != nil {
panic(err)
}
self.com.Operator(string(encryptData))
// 암호화된 데이터가 압축 컴포넌트의 오퍼레이터로
}
func main() {
sender := &EncryptComponent{key: "abcde", // 암호화 컴포넌트가 압축 컴포넌트를 가짐
com: &ZipComponent{ // 압축 컴포넌트가 샌드 컴포넌트를 가짐
com: &SendComponent{}}}
sender.Operator(("Hello World"))
// 암호화 컴포넌트의 오퍼레이터 호출
fmt.Println(sentData)
// 최종 결과값 출력
}
---------------------------------
qV�ȅ��l��Z�P�D(�ܐp��&w#̜��(�D�x��bb���
package main
import (
"fmt"
"github.com/tuckersGo/goWeb/web9/cipher"
"github.com/tuckersGo/goWeb/web9/lzw"
)
type Component interface {
Operator(string)
}
var sentData string // 암호화, 압축 결과 값
var receiveData string // 복호화, 압축 해제 결과 값
<생략>
// 복호화 컴포넌트
type DecryptComponent struct {
key string
com Component
}
func (self *DecryptComponent) Operator(data string) {
decryptData, err := cipher.Decrypt([]byte(data), self.key)
// 터커의 복호화 패키지
if err != nil {
panic(err)
}
self.com.Operator(string(decryptData))
}
// 압축해제 컴포넌트
type UnzipComponent struct {
com Component
}
func (self *UnzipComponent) Operator(data string) {
unzipData, err := lzw.Read([]byte(data))
// 터커의 압축해제 패키지
if err != nil {
panic(err)
}
self.com.Operator(string(unzipData))
}
// 복호화, 압축 해제된 값을 받아오는 컴포넌트
type ReadCompenent struct{}
func (self *ReadCompenent) Operator(data string) {
receiveData = data
}
func main() {
sender := &EncryptComponent{key: "abcde", // 암호화 컴포넌트가 압축 컴포넌트를 가짐
com: &ZipComponent{ // 압축 컴포넌트가 샌드 컴포넌트를 가짐
com: &SendComponent{},
},
}
sender.Operator(("Hello World"))
// 암호화 컴포넌트의 오퍼레이터 호출
fmt.Println(sentData)
// 최종 결과값 출력
receiver := &UnzipComponent{ // 압축해제 컴포넌트가 복호화 컴포넌트를 가짐
com: &DecryptComponent{ // 복호화 컴포넌트가 압축해제 컴포넌트를 가짐
key: "abcde",
com: &ReadCompenent{},
},
}
receiver.Operator(sentData)
// 암호화,압축 된 결과 값을 receiver의 operator로
fmt.Println(receiveData)
// 최종 결과값 출력
}
-------------------------------------
3ބ $�Xo���h��]�M�����)�D@+F�ˍz���&�B@
Hello World
Web Decorator Handler
웹 서버는 단순하게 클라이언트의 요청을 받으면 해당 데이터를 반환해주는 역할을 한다.
이 것을 기본 기능으로 보았을때 암호화, 압축, log 등은 부가 기능이 된다.
이 부가 기능들을 넣고 빼는 일이 자주 일어나기 때문에 기본 기능에 해당하는 부분에 부가 기능이 들어가 있으면, 웹 서버를 오픈한 상태에서 기본 기능 부분까지 다 수정해 주어야 한다.
때문에 데코레이터를 이용하여 각 각의 기능을 나누어 해당 부분만 수정하기 위함이다.
ex) app.go
package myapp
import (
"fmt"
"net/http"
)
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
}
// 기본페이지에 idexhandler 적용
func NewHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
return mux
}
ex) deco.go
package decoHandler
import "net/http"
type DecoratorFunc func(http.ResponseWriter, *http.Request, http.Handler)
// 3개의 인자를 갖는 펑션타입 = logger
type DecoHandler struct {
fn DecoratorFunc // 펑션타입 변수 fn
h http.Handler // http.Handler를 구현하고 있다 h
}
func (self *DecoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
self.fn(w, r, self.h)
//자체로 http.Handler의 기능을 구현하고 있으며
//호출될때 DecoratorFunc = logger 를 먼저 호출
}
func NewDecoHandler(h http.Handler, fn DecoratorFunc) http.Handler {
return &DecoHandler{
fn: fn,
h: h,
}
}
ex) main
package main
import (
"log"
"net/http"
"time"
"web4/decoHandler"
"web4/myapp"
)
// 로그를 알려주는 데코레이터
func logger(w http.ResponseWriter, r *http.Request, h http.Handler) {
// h http.Hanler 기본기능을 받음
start := time.Now()
log.Print("[LOGGER1] Started")
// Handler를 호출하기 전에 로그를 찍음
h.ServeHTTP(w, r)
// (기본기능) 핸들러 호출
log.Println("[LOGGER1] Completed", time.Since(start).Milliseconds())
// 완료된 시간을 알려준다.
}
func NewHandler() http.Handler {
h := myapp.NewHandler()
h = decoHandler.NewDecoHandler(h, logger)
// myapp.에서 만들어온 핸들러를 deco로 감쌈
// 인덱스 핸들러가 불릴때 log를 찍어준다.
return h
}
func main() {
mux := NewHandler()
http.ListenAndServe(":3000", mux)
}