github.com/packtpublishing/learning-functional-programming-in-go@v0.0.0-20230130084745-8b849f6d58c4/Chapter04/01_duck/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"errors"
     6  	"log"
     7  )
     8  const DASHES = "----------------------"
     9  
    10  type Pond struct {
    11  	BugSupply       int
    12  	StrokesRequired int
    13  }
    14  
    15  type StrokeBehavior interface {
    16  	PaddleFoot(strokeSupply *int)
    17  }
    18  
    19  type EatBehavior interface {
    20  	EatBug(strokeSupply *int)
    21  }
    22  
    23  type SurvivalBehaviors interface {
    24  	StrokeBehavior
    25  	EatBehavior
    26  }
    27  
    28  
    29  type Duck struct{}
    30  
    31  func (Duck) Stroke(s StrokeBehavior, strokeSupply *int, p Pond) (err error) {
    32  	for i := 0;  i < p.StrokesRequired; i++ {
    33  		if *strokeSupply < p.StrokesRequired - i {
    34  			err = errors.New("Our duck died!")
    35  		}
    36  		s.PaddleFoot(strokeSupply)
    37  	}
    38  	return err
    39  }
    40  
    41  func (Duck) Eat(e EatBehavior, strokeSupply *int, p Pond) {
    42  	for i := 0;  i < p.BugSupply; i++ {
    43  		e.EatBug(strokeSupply)
    44  	}
    45  }
    46  
    47  type Foot struct{}
    48  func (Foot) PaddleFoot(strokeSupply *int) {
    49  	fmt.Println("- Foot, paddle!")
    50  	*strokeSupply--
    51  }
    52  
    53  type Bill struct{}
    54  func (Bill) EatBug(strokeSupply *int) {
    55  	*strokeSupply++
    56  	fmt.Println("- Bill, eat a bug!")
    57  }
    58  
    59  func (d Duck) SwimAndEat(se SurvivalBehaviors, strokeSupply *int, ponds []Pond) {
    60  	for i := range ponds {
    61  		pond := &ponds[i]
    62  		err := d.Stroke(se, strokeSupply, *pond)
    63  		if err != nil {
    64  			log.Fatal(err)  // the duck died!
    65  		}
    66  		d.Eat(se, strokeSupply, *pond)
    67  	}
    68  }
    69  
    70  type Capabilities struct {
    71  	StrokeBehavior
    72  	EatBehavior
    73  	strokes int
    74  }
    75  
    76  func displayDuckStats(c Capabilities, ponds []Pond) {
    77  	fmt.Printf("%s\n", DASHES)
    78  	fmt.Printf("Ponds Processed:")
    79  	for _, pond := range ponds {
    80  		fmt.Printf("\n\t%+v", pond)
    81  	}
    82  	fmt.Printf("\nStrokes remaining: %+v\n", c.strokes)
    83  	fmt.Printf("%s\n\n", DASHES)
    84  }
    85  
    86  
    87  func main() {
    88  	var duck Duck
    89  	capabilities := Capabilities{
    90  		StrokeBehavior: Foot{},
    91  		EatBehavior:    Bill{},
    92  		strokes:        5,
    93  	}
    94  
    95  	ponds := []Pond{
    96  		{BugSupply: 1, StrokesRequired: 3},
    97  		{BugSupply: 1, StrokesRequired: 2},
    98  	}
    99  	duck.SwimAndEat(&capabilities, &capabilities.strokes, ponds)
   100  	displayDuckStats(capabilities, ponds)
   101  
   102  	ponds = []Pond{
   103  		{BugSupply: 2, StrokesRequired: 3},
   104  	}
   105  	duck.SwimAndEat(&capabilities, &capabilities.strokes, ponds)
   106  	displayDuckStats(capabilities, ponds)
   107  }
   108  
   109