Skip to content

Instantly share code, notes, and snippets.

@fahmifan
Created October 27, 2024 15:57
Show Gist options
  • Save fahmifan/cd287bdfa1b2c87af7863ac72fc23bb7 to your computer and use it in GitHub Desktop.
Save fahmifan/cd287bdfa1b2c87af7863ac72fc23bb7 to your computer and use it in GitHub Desktop.
Videostore from Martin Fowler Refactoring in Go
package main
import (
"fmt"
"refactoring/videostore"
)
func main() {
movieA := videostore.Movie{
Title: "Wiro Sableng",
PriceCode: videostore.REGULAR,
}
movieB := videostore.Movie{
Title: "Merapi 3",
PriceCode: videostore.NEW_RELEASE,
}
movieC := videostore.Movie{
Title: "Si Unyil",
PriceCode: videostore.CHILDREN,
}
customer := videostore.Customer{
Name: "John Doe",
}
customer.AddRental(videostore.Rental{
Movie: movieA,
DaysRented: 2,
})
customer.AddRental(videostore.Rental{
Movie: movieB,
DaysRented: 3,
})
customer.AddRental(videostore.Rental{
Movie: movieC,
DaysRented: 5,
})
statment := customer.MakeStatment()
fmt.Println(statment.PlainText())
fmt.Println("=======")
fmt.Println(statment.HTML())
}
package videostore
import "fmt"
type PriceCode int
const (
REGULAR PriceCode = iota
NEW_RELEASE
CHILDREN
)
type Movie struct {
Title string
PriceCode PriceCode
}
func (movie *Movie) OwedAmount(daysRented int) float64 {
switch movie.PriceCode {
case REGULAR:
return ChargeForRegular(daysRented)
case NEW_RELEASE:
return ChargeForNewRelease(daysRented)
case CHILDREN:
return ChargeForChildren(daysRented)
default:
return 0
}
}
func ChargeForRegular(daysRented int) float64 {
amount := float64(2)
if daysRented > 2 {
amount += float64(daysRented-2) * 1.5
}
return amount
}
func ChargeForNewRelease(daysRented int) float64 {
return float64(daysRented) * 3
}
func ChargeForChildren(daysRented int) float64 {
amount := float64(1.5)
if daysRented > 3 {
amount += float64((daysRented)-3) * 1.5
}
return amount
}
func (movie *Movie) FrequentPoints(daysRented int) int {
if movie.PriceCode == NEW_RELEASE {
return 2
}
return 1
}
type Rental struct {
Movie Movie
DaysRented int
}
func (rental *Rental) OwedAmount() float64 {
return rental.Movie.OwedAmount(rental.DaysRented)
}
func (rental *Rental) FrequentPoints() int {
return rental.Movie.FrequentPoints(rental.DaysRented)
}
type StatmentDetail struct {
MovieTitle string
OwedAmount float64
}
type Customer struct {
Name string
rentals []Rental
}
func (cust *Customer) AddRental(rental Rental) {
cust.rentals = append(cust.rentals, rental)
}
type Statement struct {
CustomerName string
TotalOwedAmount float64
FrequentRenterPoints int
Details []StatmentDetail
}
func (cust *Customer) MakeStatment() Statement {
totalAmount := float64(0)
frequentRenterPoints := 0
statment := Statement{
CustomerName: cust.Name,
Details: []StatmentDetail{},
}
for _, rental := range cust.rentals {
frequentRenterPoints += rental.FrequentPoints()
owedAmount := rental.OwedAmount()
totalAmount += owedAmount
statment.Details = append(statment.Details, StatmentDetail{
MovieTitle: rental.Movie.Title,
OwedAmount: rental.OwedAmount(),
})
}
return statment
}
func (statement *Statement) PlainText() string {
result := fmt.Sprintf("Rental Record %s\n", statement.CustomerName)
for _, detail := range statement.Details {
result += "\t" + detail.MovieTitle + "\t" + fmt.Sprint(detail.OwedAmount) + "\n"
}
result += "Amount owed is " + fmt.Sprint(statement.TotalOwedAmount) + "\n"
result += "You earned " + fmt.Sprint(statement.FrequentRenterPoints) + " frequent renter points"
return result
}
// Just example
func (statement *Statement) HTML() string {
result := fmt.Sprintf("<html>Rental Record %s\n", statement.CustomerName)
for _, detail := range statement.Details {
result += "\t" + detail.MovieTitle + "\t" + fmt.Sprint(detail.OwedAmount) + "\n"
}
result += "Amount owed is " + fmt.Sprint(statement.TotalOwedAmount) + "\n"
result += "You earned " + fmt.Sprint(statement.FrequentRenterPoints) + " frequent renter points"
return result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment