From 1328860453bb36492bc71689d6567227190a9b99 Mon Sep 17 00:00:00 2001 From: ismayilmalik Date: Mon, 1 Jan 2018 21:29:51 +0300 Subject: [PATCH] implemented chain of responsibility --- README.md | 5 ++ .../chain_of_responsibility.go | 81 +++++++++++++++++++ .../chain_of_responsibility_test.go | 36 +++++++++ 3 files changed, 122 insertions(+) create mode 100644 behavioral/chain_of_responsibility/chain_of_responsibility.go create mode 100644 behavioral/chain_of_responsibility/chain_of_responsibility_test.go diff --git a/README.md b/README.md index 33d8b75..841756a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ - [Structural patterns](#structural-patterns) - [Composition](#composition) - [Behavioral patterns](#behavioral-patterns) + - [Chain of responsibility](#chain-of-responsibility) - [Concurrency patterns](#concurrency-patterns) --- @@ -39,6 +40,10 @@ between objects. Behavio ral patterns describe not just patterns of objects or c but also the patterns of communication between them. These patterns characterize complex control flow that's difficult to follow at run-time. They shift your focus away from flow of control to let you concent ratejust on the way objects are interconnected. +### Chain of responsibility +Avoid coupling the sender of a request to its receiver by giving more than one +object a chance to handle the request. Chain the receiving objects and pass the +request along the chain until an object handles it. ## Concurrency patterns Pattenrs for concurrent work and parallel execution in Go. \ No newline at end of file diff --git a/behavioral/chain_of_responsibility/chain_of_responsibility.go b/behavioral/chain_of_responsibility/chain_of_responsibility.go new file mode 100644 index 0000000..cc62a5b --- /dev/null +++ b/behavioral/chain_of_responsibility/chain_of_responsibility.go @@ -0,0 +1,81 @@ +package chain_of_responsibility + +import ( + "errors" + "fmt" + "encoding/json" +) + +type Handler interface { + Handle(interface{}) error +} + +type Book struct { + Title string + Author string +} + +func (b Book) String() string { + return fmt.Sprintf("%b", b) +} + +type Deserializer struct { + next Handler +} + +func (h *Deserializer) Handle(data interface{}) error { + var book Book + bytes, ok := data.([]byte) + if !ok { + return errors.New("Unsupported type!") + } + + if err := json.Unmarshal(bytes, &book); err != nil { + return err + } + + if h.next != nil { + return h.next.Handle(book) + } + + return nil +} + +type Logger struct { + next Handler +} + +func (h *Logger) Handle(data interface{}) error { + book, ok := data.(Book) + if !ok { + return errors.New("Argument is not a Book instance") + } + + fmt.Println("Book received! Titlle: '%s' Author: '%s", book.Title, book.Author) + if h.next != nil { + return h.next.Handle(book) + } + + return nil +} + +type BookDb struct { + store map[string]Book + next Handler +} + +func (h *BookDb) Handle(data interface{}) error { + book, ok := data.(Book) + if !ok { + return errors.New("Argument is not a Book instance") + } + + h.store[book.Title]=book + + if h.next != nil { + return h.next.Handle(book) + } + + return nil +} + diff --git a/behavioral/chain_of_responsibility/chain_of_responsibility_test.go b/behavioral/chain_of_responsibility/chain_of_responsibility_test.go new file mode 100644 index 0000000..1b0336c --- /dev/null +++ b/behavioral/chain_of_responsibility/chain_of_responsibility_test.go @@ -0,0 +1,36 @@ +package chain_of_responsibility + +import ( + "encoding/json" + "testing" +) + +func TestCORPattern(t *testing.T) { + book := Book{"Go design patterns", "Ismayil Malik"} + bytes, _ := json.Marshal(book) + bookDb := &BookDb{ + make(map[string]Book), + nil, + } + logger := &Logger{ + next: bookDb, + } + chain := &Deserializer{ + next: logger, + } + + t.Run(`It will be unmurshalled on deserializer handler then will be logged + on logger handler and at the end will be presisted by third handler`, func(t *testing.T) { + + err := chain.Handle(bytes) + if err != nil { + t.Fatalf("Something went wrong: %s", err.Error()) + } + + storedBook := bookDb.store[book.Title] + if storedBook != book { + t.Errorf("Expected %b but got %b", book, storedBook) + } + }) + +}