# [go语言]避免过度重构

deansinaean · · 3536 次点击 · · 开始浏览

golang-nuts上有人提了一个问题[1]，询问怎么样把减少两个类似数据结构和算法的重复代码。简而言之，有两个struct：QuickFindSet和QuickUnionSet，它们各有Count, IsConnected, Find, Union等方法。他发现这两个struct的一些函数的实现是一样的，因此他希望能消除这些重复代码。

``````
// quick-find
type QuickFindSet struct {

numOfComponents uint
items []uint

}

func NewSet(n uint) QuickFindSet {

set := QuickFindSet{ numOfComponents: n, items: make([]uint, n) }
for i, _ := range set.items {

set.items[i] = uint(i)

}
return set

}

func (set *QuickFindSet) Count() uint {

return set.numOfComponents

}

func (set *QuickFindSet) IsConnected (p, q uint) bool {

return set.Find(p) == set.Find(q)

}

func (set *QuickFindSet) Find(p uint) uint {

return set.items[p]

}

func (set *QuickFindSet) Union(p, q uint) {

rootP := set.Find(p)
rootQ := set.Find(q)
if rootP == rootQ {

return

}
for i, _ := range set.items {

if set.items[i] == rootP {

set.items[i] = rootQ

}

}
set.numOfComponents--

}

// weighted quick-union
type QuickUnionSet struct {

numOfComponents uint
items []uint
sizes []uint

}

func NewSet(n uint) QuickUnionSet {

set := QuickUnionSet{ numOfComponents: n, items: make([]uint, n), sizes: make([]uint, n) }
for i, _ := range set.items {

set.items[i] = uint(i)

set.sizes[i] = uint(1)

}
return set

}

func (set *QuickUnionSet) Count() uint {

return set.numOfComponents

}

func (set *QuickUnionSet) IsConnected (p, q uint) bool {

return set.Find(p) == set.Find(q)

}

func (set *QuickUnionSet) Find(p uint) uint {

for p != set.items[p] {

p = set.items[p]

}
return p

}

func (set *QuickUnionSet) Union(p, q uint) {

rootP := set.Find(p)
rootQ := set.Find(q)
if rootP == rootQ {

return

}
if set.sizes[rootP] < set.sizes[rootQ] {

set.items[rootP] = rootQ

set.sizes[rootQ] += set.sizes[rootP]

} else {

set.items[rootQ] = rootP

set.sizes[rootP] += set.sizes[rootQ]

}
set.numOfComponents--

}
``````

``````
func (set *QuickFindSet) Count() uint {
return set.numOfComponents
}
func (set *QuickFindSet) IsConnected (p, q uint) bool {
return set.Find(p) == set.Find(q)
}
func (set *QuickUnionSet) Count() uint {
return set.numOfComponents
}
func (set *QuickUnionSet) IsConnected (p, q uint) bool {
return set.Find(p) == set.Find(q)
}
``````

代码非常的混乱以至于很难阅读
已有需求或者有潜在的需求需要修改代码

这里重复的代码非常少，只有几行代码。代码结构也比较清晰。
作为一个和业务逻辑关联不大的基础数据结构，变化的需求很小。

Russ Cox也给出了类似的意见：

1 回复  |  直到 2018-12-14 16:09:44

• 请尽量让自己的回复能够对别人有帮助
• 支持 Markdown 格式, **粗体**、~~删除线~~、``单行代码``
• 支持 @ 本站用户；支持表情（输入 : 提示），见 Emoji cheat sheet
• 图片支持拖拽、截图粘贴等方式上传

golang-nuts上有人提了一个问题[1]，询问怎么样把减少两个类似数据结构和算法的重复代码。简而言之，有两个struct：QuickFindSet和QuickUnionSet，它们各有Count, IsConnected, Find, Union等方法。他发现这两个struct的一些函数的实现是一样的，因此他希望能消除这些重复代码。

``````
// quick-find
type QuickFindSet struct {

numOfComponents uint
items []uint

}

func NewSet(n uint) QuickFindSet {

set := QuickFindSet{ numOfComponents: n, items: make([]uint, n) }
for i, _ := range set.items {

set.items[i] = uint(i)

}
return set

}

func (set *QuickFindSet) Count() uint {

return set.numOfComponents

}

func (set *QuickFindSet) IsConnected (p, q uint) bool {

return set.Find(p) == set.Find(q)

}

func (set *QuickFindSet) Find(p uint) uint {

return set.items[p]

}

func (set *QuickFindSet) Union(p, q uint) {

rootP := set.Find(p)
rootQ := set.Find(q)
if rootP == rootQ {

return

}
for i, _ := range set.items {

if set.items[i] == rootP {

set.items[i] = rootQ

}

}
set.numOfComponents--

}

// weighted quick-union
type QuickUnionSet struct {

numOfComponents uint
items []uint
sizes []uint

}

func NewSet(n uint) QuickUnionSet {

set := QuickUnionSet{ numOfComponents: n, items: make([]uint, n), sizes: make([]uint, n) }
for i, _ := range set.items {

set.items[i] = uint(i)

set.sizes[i] = uint(1)

}
return set

}

func (set *QuickUnionSet) Count() uint {

return set.numOfComponents

}

func (set *QuickUnionSet) IsConnected (p, q uint) bool {

return set.Find(p) == set.Find(q)

}

func (set *QuickUnionSet) Find(p uint) uint {

for p != set.items[p] {

p = set.items[p]

}
return p

}

func (set *QuickUnionSet) Union(p, q uint) {

rootP := set.Find(p)
rootQ := set.Find(q)
if rootP == rootQ {

return

}
if set.sizes[rootP] < set.sizes[rootQ] {

set.items[rootP] = rootQ

set.sizes[rootQ] += set.sizes[rootP]

} else {

set.items[rootQ] = rootP

set.sizes[rootP] += set.sizes[rootQ]

}
set.numOfComponents--

}
``````

``````
func (set *QuickFindSet) Count() uint {
return set.numOfComponents
}
func (set *QuickFindSet) IsConnected (p, q uint) bool {
return set.Find(p) == set.Find(q)
}
func (set *QuickUnionSet) Count() uint {
return set.numOfComponents
}
func (set *QuickUnionSet) IsConnected (p, q uint) bool {
return set.Find(p) == set.Find(q)
}
``````

代码非常的混乱以至于很难阅读
已有需求或者有潜在的需求需要修改代码

这里重复的代码非常少，只有几行代码。代码结构也比较清晰。
作为一个和业务逻辑关联不大的基础数据结构，变化的需求很小。

Russ Cox也给出了类似的意见：