From 9651c9747d856c1504c2fcd4c099a35f9943ee14 Mon Sep 17 00:00:00 2001 From: Jian Han Date: Wed, 10 Jan 2018 21:42:52 +1000 Subject: [PATCH] added builder pattern --- .../concurrent_pattern/pipeline/main.go | 67 +++++++++++++++ .../creational/builder/main.go | 84 +++++++++++++++++++ .../creational/builder/main_test.go | 24 ++++++ 3 files changed, 175 insertions(+) create mode 100644 go_design_pattern_book/concurrent_pattern/pipeline/main.go create mode 100644 go_design_pattern_book/creational/builder/main.go create mode 100644 go_design_pattern_book/creational/builder/main_test.go diff --git a/go_design_pattern_book/concurrent_pattern/pipeline/main.go b/go_design_pattern_book/concurrent_pattern/pipeline/main.go new file mode 100644 index 0000000..cff129c --- /dev/null +++ b/go_design_pattern_book/concurrent_pattern/pipeline/main.go @@ -0,0 +1,67 @@ +package main + +import ( + "fmt" + "sync" +) + +func main() { + in := gen(2, 3) + + // Distribute the sq work across two goroutines that both read from in. + c1 := sq(in) + c2 := sq(in) + + // Consume the merged output from c1 and c2. + for n := range merge(c1, c2) { + fmt.Println(n) // 4 then 9, or 9 then 4 + } +} + +func gen(nums ...int) <-chan int { + out := make(chan int, len(nums)) + go func() { + for _, n := range nums { + out <- n + } + close(out) + }() + return out +} + +func sq(in <-chan int) <-chan int { + out := make(chan int) + go func() { + for n := range in { + out <- n * n + } + close(out) + }() + return out +} + +func merge(cs ...<-chan int) <-chan int { + var wg sync.WaitGroup + out := make(chan int, 1) // enough space for the unread inputs + + // Start an output goroutine for each input channel in cs. output + // copies values from c to out until c is closed, then calls wg.Done. + output := func(c <-chan int) { + for n := range c { + out <- n + } + wg.Done() + } + wg.Add(len(cs)) + for _, c := range cs { + go output(c) + } + + // Start a goroutine to close out once all the output goroutines are + // done. This must start after the wg.Add call. + go func() { + wg.Wait() + close(out) + }() + return out +} diff --git a/go_design_pattern_book/creational/builder/main.go b/go_design_pattern_book/creational/builder/main.go new file mode 100644 index 0000000..75969b1 --- /dev/null +++ b/go_design_pattern_book/creational/builder/main.go @@ -0,0 +1,84 @@ +package main + +// Builder design pattern tried to +// 1. Abstract complex creations so that object creation is seperated from object user. +// 2. Create an object step by step by filling it's fields and creating embedded objects. +// 3. Reuse the object creation algorithm between many objects. +// Builder design pattern is often described as a relationship between a director and builders. +// Director in charge of construction of objects. +// Builders are the ones that return actual products. + +// BuildProcess is a procceding interface defines each steps needed for building vehicle. +type BuildProcess interface { + SetWheels() BuildProcess + SetSeats() BuildProcess + SetStructure() BuildProcess + GetVehicle() VehicleProduct +} + +// VehicleProduct is the product that we want to retrieve while using manufacturing. +type VehicleProduct struct { + Wheels int + Seats int + Structure string +} + +// ManufacturingDirector is the one that in charge of accepting builders. +// It has a Construct method that will use builder that is stored in Manufacturing, and will reproduce the required steps. +type ManufacturingDirector struct { + builder BuildProcess +} + +func (f *ManufacturingDirector) Construct() { + f.builder.SetSeats().SetStructure().SetWheels() +} + +func (f *ManufacturingDirector) SetBuilder(b BuildProcess) { + f.builder = b +} + +type CarBuilder struct { + v VehicleProduct +} + +func (c *CarBuilder) SetWheels() BuildProcess { + c.v.Wheels = 4 + return c +} + +func (c *CarBuilder) SetSeats() BuildProcess { + c.v.Seats = 5 + return c +} + +func (c *CarBuilder) SetStructure() BuildProcess { + c.v.Structure = "Car" + return c +} + +func (c *CarBuilder) GetVehicle() VehicleProduct { + return c.v +} + +type BikeBuilder struct { + v VehicleProduct +} + +func (b *BikeBuilder) SetWheels() BuildProcess { + b.v.Wheels = 2 + return b +} + +func (b *BikeBuilder) SetSeats() BuildProcess { + b.v.Seats = 2 + return b +} + +func (b *BikeBuilder) SetStructure() BuildProcess { + b.v.Structure = "Bike" + return b +} + +func (b *BikeBuilder) GetVehicle() VehicleProduct { + return b.v +} diff --git a/go_design_pattern_book/creational/builder/main_test.go b/go_design_pattern_book/creational/builder/main_test.go new file mode 100644 index 0000000..37d6a5e --- /dev/null +++ b/go_design_pattern_book/creational/builder/main_test.go @@ -0,0 +1,24 @@ +package main + +import ( + "testing" +) + +func TestBuilderPatter(t *testing.T) { + manufacturingComplex := ManufacturingDirector{} + carBuilder := &CarBuilder{} + manufacturingComplex.SetBuilder(carBuilder) + manufacturingComplex.Construct() + car := carBuilder.GetVehicle() + if car.Wheels != 4 { + t.Errorf("number of wheels in car should be 4, it is %d", car.Seats) + } + + bikeBuilder := &BikeBuilder{} + manufacturingComplex.SetBuilder(bikeBuilder) + manufacturingComplex.Construct() + bike := bikeBuilder.GetVehicle() + if bike.Wheels != 2 { + t.Errorf("number of wheels on bike should be 2, it is %d", bike.Seats) + } +}