我有以下类型:
type entity struct {
components []Component
}
func NewEntity(componentsLength ComponentType) Entity {
return &entity{
components: make([]Component, componentsLength),
}
}
编码时,我注意到以下重复模式:
func (e *entity) HasComponent(components ...Component) bool {
for _, c := range components {
if e.components[c.Type()] == nil {
return false
}
}
return true
}
func (e *entity) HasAnyComponent(components ...Component) bool {
for _, c := range components {
if e.components[c.Type()] != nil {
return true
}
}
return false
}
当您为不同类型编写类似的函数时,使用大量重复代码似乎没问题。但是,在这种情况下,类型是相同的。我仍然无法重构代码以概括使用for
循环和if
语句。
如何重构这些函数以便列表处理很常见,但布尔运算符和值是否被抽象出来?我应该吗?
答案 0 :(得分:0)
是的,我认为您应该重构此代码,不仅仅是为了使其更紧凑,而是为了更好地表达您正在执行的操作的集合理论性质。这两个函数都在询问有关e.components
和components
的交集的问题。
您HasComponent
基本上要说的是HasAllComponents
- 可能被称为e.components
- 是components
和components
的交集等于{{ 1}}。换句话说,交叉点的大小与components
的大小相同。
至于HasAnyComponent
,您所说的是十字路口的大小至少为一。
通过测试交叉点的大小,可以简洁地表达这两个函数,您可以使用具有此签名的函数来获取该函数:
func (e *entity) CountComponents(components ...Component) int
但是,您的原始代码具有短路逻辑,一旦知道答案,就会停止查看其他组件。您可以将这样一个短路循环合并到具有此签名的函数中:
func (e *entity) HasMinimumComponents(minimum int, components ...Component) bool
在循环中,每count
递增一个e.components[c.Type()] != nil
变量。 true
尽快返回count >= minimum
。
现在,您可以使用单行正文有效地实现HasAllComponents
:
return entity.HasMinimumComponents(len(components), components...)
HasAnyComponent
的身体变成了:
return entity.HasMinimumComponents(1, components...)
以下是一个用稍微不同的数据类型实现这个想法的程序。我定义了一个包含Entity
的更抽象的map[int]bool
。你应该毫不费力地将这个想法适应你自己的程序。
package main
import (
"fmt"
)
type Entity struct {
ValueMap map[int]bool
}
func MakeEntity(values ...int) *Entity {
entity := Entity{map[int]bool{}}
for _, value := range values {
entity.ValueMap[value] = true
}
return &entity
}
func (entity *Entity) HasMinimumValues(minimum int, values ...int) bool {
count := 0
if minimum == 0 {
return true
}
for _, value := range values {
if entity.ValueMap[value] {
count++
if count >= minimum {
return true
}
}
}
return false
}
func (entity *Entity) HasAllValues(values ...int) bool {
return entity.HasMinimumValues(len(values), values...)
}
func (entity *Entity) HasAnyValue(values ...int) bool {
return entity.HasMinimumValues(1, values...)
}
func main() {
entity := MakeEntity(1, 3, 5, 7, 9)
fmt.Printf("%t\n", entity.HasAllValues(3, 9))
fmt.Printf("%t\n", entity.HasAllValues(3, 9, 12))
fmt.Printf("%t\n", entity.HasAnyValue(9, 12, 15))
fmt.Printf("%t\n", entity.HasAnyValue(12, 15))
}