DEV Community

Shubham Sethi
Shubham Sethi

Posted on

1

Strategy Pattern in Go

Imagine you have to build a program that simulates birds.

There can be different type of birds with different flying behaviours.

A parrot that flies low , an eagle that flies high and ostrich which doesn’t fly at all

We will start with Bird interface.

// Interface
type Bird interface {
    Fly()
    Display()
}
Enter fullscreen mode Exit fullscreen mode

So anything that implements Fly() and Display() is a Bird.

A parrot

type Parrot struct {
    color string
}

func (p *Parrot) Fly() {
    fmt.Println("I can fly")
}

func (p *Parrot) Display() {
    fmt.Printf("I am a Parrot . I have color =%s", p.color)
}
Enter fullscreen mode Exit fullscreen mode

or an Eagle

type Eagle struct {
    color string
}

func (p *Eagle) Fly() {
    fmt.Println("I can fly high")
}

func (p *Eagle) Display() {
    fmt.Printf("I am a Eagle . I have color =%s", p.color)
}
Enter fullscreen mode Exit fullscreen mode

As you can see the Fly() is common mechanism for lot of bids, so we can move this into a common construct.

In Java, we would create an abstract class, which has some common method implemented and later extend the abstract class to implement varying behaviour.

In Go we can do so be creating a type that partially implements Fly() method

//abstracting out just flying behaviour

type FlyStrategy struct {
    doFly FlyBehaviour
}

func (f *FlyStrategy) Fly() {
    f.doFly()
}

Enter fullscreen mode Exit fullscreen mode

We extract out how a bird flies as FlyBehaviour

type FlyBehaviour func()

func FlywithWings() {
   fmt.Println("I am  flying with my wings")
}

func FlyNoWay() {
   fmt.Println("I can't fly")
}

func FlyHigh(){
   fmt.Println("I am  flying high")
}
Enter fullscreen mode Exit fullscreen mode

Now to extend this behaviour in Java we would use extend but Go doesn't support inheritance in the classical sense; instead, in encourages composition as a way to extend the functionality of types. Go supports embedding of structs and interfaces to express a more seamless composition of types.

So to extend FlyStrategy we will simply embed it inside Parrot type

// Implementation of Parrot with FlyStrategy embed
type Parrot struct {
    color string
    FlyStrategy
}

func (p *Parrot) Display() {
    fmt.Printf("I am a Parrot . I have color = %s", p.color)
}

func main() {

    var greenParrot Bird

    greenParrot = &Parrot{
        color:       "green",
        FlyStrategy: FlyStrategy{doFly: FlywithWings},
    }

    greenParrot.Fly()
    greenParrot.Display()

}
Enter fullscreen mode Exit fullscreen mode

Advantage of this pattern is that we can dynamically update flying strategy .

// Interface
type Bird interface {
    Fly()
    Display()
//new
    UpdateFlyStrategy(flyb FlyBehaviour)
}

....
....

type FlyStrategy struct {
    doFly FlyBehaviour
}

func (f *FlyStrategy) Fly() {
    f.doFly()
}

//new
func (f *FlyStrategy) UpdateFlyStrategy(flyb FlyBehaviour) {
    f.doFly = flyb
}

....
....

greenParrot.UpdateFlyStrategy(FlyHigh)
greenParrot.Fly()
Enter fullscreen mode Exit fullscreen mode

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (1)

Collapse
 
parmcoder profile image
Possawat Sanorkam

Does this work as a proxy?

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more