From 5fdf4a775d6044b33f1debbd4f46407fdca48e97 Mon Sep 17 00:00:00 2001 From: DH Date: Sun, 13 Feb 2022 18:11:26 +0900 Subject: [PATCH 1/3] creational/builder: implement the abstract factory --- README.md | 2 +- creational/abstract-factory.md | 55 ++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 creational/abstract-factory.md diff --git a/README.md b/README.md index 7d9f5f7..30ebd71 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ A curated collection of idiomatic design & application patterns for Go language. | Pattern | Description | Status | |:-------:|:----------- |:------:| -| [Abstract Factory](/creational/abstract_factory.md) | Provides an interface for creating families of releated objects | ✘ | +| [Abstract Factory](/creational/abstract_factory.md) | Provides an interface for creating families of releated objects | ✔ | | [Builder](/creational/builder.md) | Builds a complex object using simple objects | ✔ | | [Factory Method](/creational/factory.md) | Defers instantiation of an object to a specialized function for creating instances | ✔ | | [Object Pool](/creational/object-pool.md) | Instantiates and maintains a group of objects instances of the same type | ✔ | diff --git a/creational/abstract-factory.md b/creational/abstract-factory.md new file mode 100644 index 0000000..330fdd9 --- /dev/null +++ b/creational/abstract-factory.md @@ -0,0 +1,55 @@ +# Abstract Factory Method Pattern + +Abstract Factory method creational design pattern allows providing interface that creating objects without having to specify the exact type of the object that will be created. + +## Implementation + +The example implementation shows how to make a phone from different copmanies. + +### Types + +```go +package company + +type iCompnayFactory interface { + makePhone() iPhone +} +``` + +### Different Implementations + +```go +package company + +type CompnayType int + +const ( + SAMSNUG CompnayType = iota + APPLE +) + +func getCompnayFactory(compnay CompnayType) (iCompnayFactory, error) { + switch compnay { + case SAMSNUG: + return &samsungFactory{}, nil + case APPLE: + return &appleFactory{}, nil + default: + return nil, fmt.Errorf(/* .. */) + } +} +``` + +## Usage + +With the abstract factory method, the user can provide an interface for creating families of releated objects. + +```go +appleFactory, _ := getCompnayFactory(APPLE) +applePhone := appleFactory.makePhone(); +applePhone.makeCall(/*...*/); + +samsungFactory, _ := getCompnayFactory(SAMSNUG) +samsungPhone := samsungFactory.makePhone(); +samsungPhone.makeCall(/*...*/); +``` From 16eeba3b7395eaf85abc2a01b127a2968c7f12a2 Mon Sep 17 00:00:00 2001 From: DH Date: Sun, 13 Feb 2022 18:12:45 +0900 Subject: [PATCH 2/3] creational/builder: implement the abstract factory --- creational/{abstract-factory.md => abstract_factory.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename creational/{abstract-factory.md => abstract_factory.md} (100%) diff --git a/creational/abstract-factory.md b/creational/abstract_factory.md similarity index 100% rename from creational/abstract-factory.md rename to creational/abstract_factory.md From d1a1cd47252fa8e37c292bd5a8bb3973094cf8ad Mon Sep 17 00:00:00 2001 From: DH Date: Sun, 13 Feb 2022 20:13:51 +0900 Subject: [PATCH 3/3] add state, composite pattern --- README.md | 4 +-- behavioral/state.md | 59 +++++++++++++++++++++++++++++++++++ structural/composite.md | 68 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 behavioral/state.md create mode 100644 structural/composite.md diff --git a/README.md b/README.md index 30ebd71..910be1b 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ A curated collection of idiomatic design & application patterns for Go language. | Pattern | Description | Status | |:-------:|:----------- |:------:| | [Bridge](/structural/bridge.md) | Decouples an interface from its implementation so that the two can vary independently | ✘ | -| [Composite](/structural/composite.md) | Encapsulates and provides access to a number of different objects | ✘ | +| [Composite](/structural/composite.md) | Encapsulates and provides access to a number of different objects | ✔ | | [Decorator](/structural/decorator.md) | Adds behavior to an object, statically or dynamically | ✔ | | [Facade](/structural/facade.md) | Uses one type as an API to a number of others | ✘ | | [Flyweight](/structural/flyweight.md) | Reuses existing instances of objects with similar/identical state to minimize resource usage | ✘ | @@ -42,7 +42,7 @@ A curated collection of idiomatic design & application patterns for Go language. | [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ | | [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ | | [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ | -| [State](/behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state | ✘ | +| [State](/behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state | ✔ | | [Strategy](/behavioral/strategy.md) | Enables an algorithm's behavior to be selected at runtime | ✔ | | [Template](/behavioral/template.md) | Defines a skeleton class which defers some methods to subclasses | ✘ | | [Visitor](/behavioral/visitor.md) | Separates an algorithm from an object on which it operates | ✘ | diff --git a/behavioral/state.md b/behavioral/state.md new file mode 100644 index 0000000..f3c9f55 --- /dev/null +++ b/behavioral/state.md @@ -0,0 +1,59 @@ +# Strategy Pattern +Strategy behavioral design pattern allow an object alter its behavior when its internal state changes. The object will appear on change its class. + +## Implementation +```go +package state +type State interface { + executeState(c *Context) +} + +type Context struct { + StepIndex int + StepName string + Current State +} + +type StartState struct{} + +func (s *StartState) executeState(c *Context) { + c.StepIndex = 1 + c.StepName = "start" + c.Current = &StartState{} +} + +type InprogressState struct{} + +func (s *InprogressState) executeState(c *Context) { + c.StepIndex = 2 + c.StepName = "inprogress" + c.Current = &InprogressState{} +} + +type StopState struct{} + +func (s *StopState) executeState(c *Context) { + c.StepIndex = 3 + c.StepName = "stop" + c.Current = &StopState{} +} +``` + +## Usage + +```go + context := &Context{} + var state State + + state = &StartState{} + state.executeState(context) + fmt.Println("state: ", context) + + state = &InprogressState{} + state.executeState(context) + fmt.Println("state: ", context) + + state = &StopState{} + state.executeState(context) + fmt.Println("state: ", context) +``` \ No newline at end of file diff --git a/structural/composite.md b/structural/composite.md new file mode 100644 index 0000000..19aa197 --- /dev/null +++ b/structural/composite.md @@ -0,0 +1,68 @@ +# Composite Pattern +Composite structural pattern allows composing objects into a tree-like structure and work with the it as if it was a singular object. + +## Interface +```go +package main + +import "fmt" + +type file struct { + name string +} + +func (f *file) search(keyword string) { + fmt.Printf("Searching for keyword %s in file %s\n", keyword, f.name) +} + +func (f *file) getName() string { + return f.name +} +``` + +## Implementation +`search` function will operate applies to both files and folders. For a file, it will just look into the contents of the file; for a folder, it will go through all files of that folder to find that keyword. + +```go +package main + +import "fmt" + +type folder struct { + components []component + name string +} + +func (f *folder) search(keyword string) { + fmt.Printf("Serching recursively for keyword %s in folder %s\n", keyword, f.name) + for _, composite := range f.components { + composite.search(keyword) + } +} + +func (f *folder) add(c component) { + f.components = append(f.components, c) +} +``` + +## Usage +```go +file1 := &file{name: "File1"} +file2 := &file{name: "File2"} +file3 := &file{name: "File3"} + +folder1 := &folder{ + name: "Folder1", +} + +folder1.add(file1) + +folder2 := &folder{ + name: "Folder2", +} +folder2.add(file2) +folder2.add(file3) +folder2.add(folder1) + +folder2.search("rose") +```