Created
July 13, 2023 15:27
-
-
Save jerryan999/ed63f9a0090cd17ee665809948db1617 to your computer and use it in GitHub Desktop.
specification pattern in golang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "fmt" | |
type Employee struct { | |
name string | |
age int | |
salary int | |
location string | |
} | |
type EmployeeSpecification interface { | |
IsSatisfiedBy(Employee) bool | |
} | |
type AgeSpecification struct { | |
minAge int | |
maxAge int | |
} | |
func (s AgeSpecification) IsSatisfiedBy(e Employee) bool { | |
return e.age >= s.minAge && e.age <= s.maxAge | |
} | |
type SalarySpecification struct { | |
minSalary int | |
maxSalary int | |
} | |
func (s SalarySpecification) IsSatisfiedBy(e Employee) bool { | |
return e.salary >= s.minSalary && e.salary <= s.maxSalary | |
} | |
type LocationSpecification struct { | |
location string | |
} | |
func (s LocationSpecification) IsSatisfiedBy(e Employee) bool { | |
return e.location == s.location | |
} | |
type AndSpecification struct { | |
specifications []EmployeeSpecification | |
} | |
func (s AndSpecification) IsSatisfiedBy(e Employee) bool { | |
for _, spec := range s.specifications { | |
if !spec.IsSatisfiedBy(e) { | |
return false | |
} | |
} | |
return true | |
} | |
type OrSpecification struct { | |
specifications []EmployeeSpecification | |
} | |
func (s OrSpecification) IsSatisfiedBy(e Employee) bool { | |
for _, spec := range s.specifications { | |
if spec.IsSatisfiedBy(e) { | |
return true | |
} | |
} | |
return false | |
} | |
type UserRepository interface { | |
Save(employee Employee) error | |
FindAll(spec EmployeeSpecification) ([]Employee, error) | |
} | |
type MemoryUserRepository struct { | |
employees []Employee | |
} | |
func (r MemoryUserRepository) Save(employee Employee) error { | |
r.employees = append(r.employees, employee) | |
return nil | |
} | |
func (r MemoryUserRepository) FindAll(spec EmployeeSpecification) ([]Employee, error) { | |
var filteredEmployees []Employee | |
for _, employee := range r.employees { | |
if spec.IsSatisfiedBy(employee) { | |
filteredEmployees = append(filteredEmployees, employee) | |
} | |
} | |
return filteredEmployees, nil | |
} | |
func main() { | |
employees := []Employee{ | |
{"Alice", 25, 50000, "New York"}, | |
{"Bob", 30, 60000, "San Francisco"}, | |
{"Charlie", 35, 70000, "New York"}, | |
{"David", 40, 80000, "San Francisco"}, | |
{"Edward", 45, 90000, "New York"}, | |
{"Flynn", 50, 100000, "San Francisco"}, | |
} | |
repo := MemoryUserRepository{employees: employees} | |
for _, employee := range employees { | |
repo.Save(employee) | |
} | |
// filter employees by age | |
ageSpec := AgeSpecification{minAge: 30, maxAge: 45} | |
filteredEmployees, _ := repo.FindAll(ageSpec) | |
fmt.Println(filteredEmployees) | |
// composite specification | |
var comSpec EmployeeSpecification | |
salarySpec := SalarySpecification{minSalary: 60000, maxSalary: 90000} | |
locationSpec := LocationSpecification{location: "San Francisco"} | |
comSpec = AndSpecification{specifications: []EmployeeSpecification{ageSpec, salarySpec, locationSpec}} | |
filteredEmployees, _ = repo.FindAll(comSpec) | |
fmt.Println(filteredEmployees) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment