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

stevewang · · 1793 次点击 · · 开始浏览

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)
}

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

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

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

0 回复

• 请尽量让自己的回复能够对别人有帮助
• 支持 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)
}

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

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

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