added builder pattern

This commit is contained in:
Jian Han 2018-01-10 21:42:52 +10:00
parent 4dd2bfaabf
commit 9651c9747d
3 changed files with 175 additions and 0 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}