Los patrones de diseño, son dinámicos, hay que adaptarlos para cada caso. Si bien hemos aprendido que suelen usarse en conjunto con otros, hay casos en los que podemos aplicarlos aislados.

El patron criteria nos permite filtrar, una lista de instancias, en base a criterios. Para ello definiremos implementaciones de la interfaz ICriteria, implementando por otro lado cada criterio de filtrado.

Una vez definida toda la estructura, montaremos los filtros en orden que esperamos que se vaya aplicando.

En Java podríamos poner, todos los métodos AND, ORD, etc en una misma clase utilizando genéricos.

En este ejemplo, definiré objetos independientes, para gestionar las operaciones lógicas, no por ello, esta implementación debería ser la única que podéis aplicar.

No sigáis este código al pie de la letra, ser creativos, adaptarlo. Vayamos a la implementación en go!!!!

Criteria.go

package main

type Criteria interface {
	Apply(properties []Property) []Property
}

type OrCriteria struct {
	Left  Criteria
	Right Criteria
}

func (or OrCriteria) Apply(properties []Property) []Property {
	result := or.Left.Apply(properties)
	return append(result, or.Right.Apply(properties)...)
}

type AndCriteria struct {
	Left  Criteria
	Right Criteria
}

func (and AndCriteria) Apply(properties []Property) []Property {
	result := and.Left.Apply(properties)
	return and.Right.Apply(result)
}

type CriteriaPool struct{}

func (c CriteriaPool) Apply(properties []Property) []Property {
	result := []Property{}
	for _, property := range properties {
		if property.Pool {
			result = append(result, property)
		}
	}
	return result
}

type CriteriaFlat struct{}

func (c CriteriaFlat) Apply(properties []Property) []Property {
	result := []Property{}
	for _, property := range properties {
		if "Flat" == property.Type {
			result = append(result, property)
		}
	}
	return result
}

type CriteriaHouse struct{}

func (c CriteriaHouse) Apply(properties []Property) []Property {
	result := []Property{}
	for _, property := range properties {
		if "House" == property.Type {
			result = append(result, property)
		}
	}
	return result
}

Porperty.go

package main

type Property struct {
	Name string
	Type string
	Pool bool
}

func NewProperty(name string, properType string, pool bool) Property {
	return Property{Name: name, Type: properType, Pool: pool}
}

How to use

package main

import "fmt"

func main() {
	result := []Property{}
	result = append(result, NewProperty("Flat 1", "Flat", false))
	result = append(result, NewProperty("Flat 2", "Flat", false))
	result = append(result, NewProperty("House 1", "House", false))
	result = append(result, NewProperty("Flat 4", "Flat", false))
	result = append(result, NewProperty("House 2", "House", true))
	result = append(result, NewProperty("House 3", "House", false))
	result = append(result, NewProperty("Flat 3", "Flat", false))
	result = append(result, NewProperty("House 5", "House", true))
	result = append(result, NewProperty("House 4", "House", false))
	result = append(result, NewProperty("Flat 3", "Flat", true))

	PrintPropertyList("Flat", CriteriaFlat{}, result)

	PrintPropertyList("House", CriteriaHouse{}, result)

	PrintPropertyList("Pool", CriteriaPool{}, result)

	PrintPropertyList("House or Pool", OrCriteria{CriteriaHouse{}, CriteriaPool{}}, result)

	PrintPropertyList("House and Pool", AndCriteria{CriteriaHouse{}, CriteriaPool{}}, result)
}

func PrintPropertyList(filter string, criteria Criteria, properties []Property) {
	fmt.Printf("\nFiltering by %s\n", filter)
	for _, property := range criteria.Apply(properties) {
		fmt.Printf("Name: %s, Type: %s, Pool: %t\n", property.Name, property.Type, property.Pool)
	}
}

Seguirme en GitHub, twitter, me ayudará a continuar generando contenido!.

Deja una respuesta