Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 18, 2020 12:05 pm GMT

FlyWeight Design Pattern in Go

Hey there!

New week, new design pattern to learn. This week I'm writing about the FlyWeight Design pattern. This pattern is a little bit different from the ones I've written before because I feel like most of it is oriented toward memory conservation on your computing which we pretty much don't care about on our daily basis. However, if you are working with distributed systems, old computers, or enormous database sets, maybe this pattern is for you.

So, let's imagine that you want to work on an MMO game (massive multiplayer online). This would require you to handle a lot of users with their first name, Lastname and username. A lot of this information would be repeated through your dataset, so let's see what we can do.

Let's create a simple struct for our Users with their full name as an attribute:

type User struct {    FullName string}func NewUser(fullName string) *User {    return &User{FullName: fullName}}
Enter fullscreen mode Exit fullscreen mode

And we need to initialize some users on our main function:

    u1 := NewUser("John Doe")    u2 := NewUser("Jane Doe")    u3 := NewUser("Jane Smith")
Enter fullscreen mode Exit fullscreen mode

This is where my point is beginning to make sense. See, the name Jane and the surname Doe are both repeated and we are storing them both times in our database. If we had a limited resource database this would be a huge problem when 700 Jan-Michael Vincent join our application.

Then, let's make our application memory oriented. To achieve this, we are going to create a new User struct and a string slice to store all the names:

var allNames []stringtype User2 struct {    names []uint8}
Enter fullscreen mode Exit fullscreen mode

The interesting thing is that now the new User is not going to store a string for the name but a int8 slice. The downside of this implementation is that the New User constructor will require more processing power.

func NewUser2(fullName string) *User2 {    getOrAdd := func(s string) uint8 {        for i := range allNames {            if allNames[i] == s {                return uint8(i)            }        }        allNames = append(allNames, s)        return uint8(len(allNames) - 1)    }    result := User2{}    parts := strings.Split(fullName, " ")    for _, p := range parts {        result.names = append(result.names, getOrAdd(p))    }    return &result}
Enter fullscreen mode Exit fullscreen mode

This method has an internal function declared which receives a string (our name) and returns us the position on the allNames slice where that name is. If it's not there, it will store it on the last position of the array and give us the position back. Then the constructor will use this internal function to store or retrieve each of the strings on our name (divided by a space).

Every time we need a New User's Full Name we will use a method that will reconstruct it's name:

func (u *User2) FullName() string {    var parts []string    for _, id := range u.names {        parts = append(parts, allNames[id])    }    return strings.Join(parts, " ")}
Enter fullscreen mode Exit fullscreen mode

Now let's go to our main function to test what we've created:

    john := NewUser("John Doe")    jane := NewUser("Jane Doe")    alsoJane := NewUser("Jane Smith")    fmt.Println(john.FullName)    fmt.Println(jane.FullName)    fmt.Println(alsoJane.FullName)    fmt.Println("Memory taken by users:",        len([]byte(john.FullName))+            len([]byte(jane.FullName))+            len([]byte(alsoJane.FullName)))    john2 := NewUser2("John Doe")    jane2 := NewUser2("Jane Doe")    alsoJane2 := NewUser2("Jane Smith")    totalMem := 0    for _, a := range allNames {        totalMem += len([]byte(a))    }    totalMem += len(john2.names)    totalMem += len(jane2.names)    totalMem += len(alsoJane2.names)    fmt.Println("Memory taken by users2", totalMem)
Enter fullscreen mode Exit fullscreen mode

We are creating 3 Users and 3 Users2 and we are printing how much memory do each of the structs consume:

go run main.goJohn DoeJane DoeJane SmithMemory taken by users: 26Memory taken by users2 22
Enter fullscreen mode Exit fullscreen mode

We are saving 4 bytes on this example. It ain't much but it's honest work memory saved on 3 strings. When names begin to get redundant on your database these 4 bytes will multiply exponentially saving a lot of memory.

As I stated before, this Design Pattern is a little bit different from the ones I wrote of before. It's memory oriented instead of Behaviour oriented so use it when in need instead of just pushing random patterns all over your applications.

That's it for this week. Hope you liked it.
Happy coding


Original Link: https://dev.to/tomassirio/flyweight-design-pattern-in-go-463o

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To