2016-07-19 1 views
1

코드 중복 문제를 해결하기 위해 "go-way"를 찾는데 어려움을 겪고 있습니다. 여기에 문제가 있습니다. 다음 고려 :Golang의 코드 중복 줄이기

type (
    WithKey interface { 
    key() string 
    } 

    SharedFunctionality interface { 
    WithKey 
    MethodA() string 
    MethodB() string 
    // ... etc ... 
    } 

    FirstType struct { ... } 
    SecondType struct { ... } 
    // ... etc ... 
) 
func (ft *FirstType) key() string { ... } 
func (st *SecondType) key() string { ... } 

지금, SharedFunctionality의 방법은 단지 key() 방법의 결과에 따라 달라집니다. 내가 좋아하는 그들을 구현할 수있는 다음과 같은 : 내가이 접근 방식에 대해 싫어하는 것은 내가 더 많은 종류의 (ThirdType, FourthType 등)를 추가로 내가 SharedFunctionality에 더 많은 방법을 추가 또는, 내가 톤을 추가해야한다는 것입니다

func runMethodA(k WithKey) string { 
    key := k.key() 
    // do something and return a string 
} 
func runMethodB(k WithKey) string { 
    key := k.key() 
    // do something else and return a string 
} 

func (ft *FirstType) MethodA() string { return runMethodA(ft) } 
func (ft *FirstType) MethodB() string { return runMethodB(ft) } 
func (st *SecondType) MethodA() string { return runMethodA(st) } 
func (st *SecondType) MethodB() string { return runMethodB(st) } 

보일러 플레이트 코드 ... 구체적으로 SharedFunctionality의 M 메소드와 N 타입의 경우 위의 4와 같은 M * N 한 행을 사용해야합니다. 즉

func (k WithKey) MethodA() string { 
    key := k.key() 
    // do something 
} 

: 나는 사랑을 할 것입니다 무엇

같은 일을하다 내가 인터페이스 유형에 방법을 정의 싶어요. 의미 : "WithKey"를 구현하는 모든 객체는 자동으로 MethodA() string, MethodB() string 등을 얻습니다. 따라서 자동으로 SharedFunctionality 인터페이스를 구현합니다. 뭔가 기본 메서드Java 인터페이스에 있습니다.

는 그러나, 나는 ... 그것이 인터페이스 유형에 메서드를 정의하는 것은 불가능 알고

이 문제를 해결의 이동 방향은 무엇입니까

?

type SharedFuncStruct struct { 
    WithKey 
} 
func (sfs *SharedFuncStruct) MethodA() string { 
    key := sfs.key() 
    // whatever 
} 
// same for MethodB() 

그리고 그것을 사용하는가, 내가 좋아하는 일을 할 것입니다 :

나는이 방법 구현 다음 인터페이스 유형의 익명 필드 구조체를 만든 것 접근을 본 적이 :

first := ... getFirstTypeValue() 
sfs := &SharedFuncStruct{first} 
sfs.MethodA() // etc 

작동하는 것처럼 보이지만 여전히 상용구 코드가 너무 많습니다.

다른 대안이 있습니까?

+0

당신은 당신의 선택을 거의 설명했습니다. 그리고 아래 dave의 대답을보십시오. 그리고 이것에 대해 생각해 봅시다. 구체적인 타입이'key()'외에'MethodA()'메소드를 이미 가지고 있다면 어떻게 될까요? 최소한 _embedding_은'MethodA()'가 의미하는 바를 ("가장 얕은 깊이"_에서) 모호하지 않게 만든다. – icza

+0

당신의 질문은 근본적으로 "구현 상속과 가상 메소드를 어떻게해야합니까?"하지만 아마도 xy 문제가 있다고 생각합니다. http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem. 당신이하고있는 일에 대한 약간의 맥락을 묘사한다면 자바 스타일의 객체 지향 디자인에 뿌리를두고 있지 않은 해결책이있을 것입니다. –

답변

1

재미있는 사실이다. 당신은 효과적으로 인터페이스에 메소드를 정의하려면이 옵션을 사용할 수 있습니다 다음 key() string 방법을 (아무거나를 저장할 수 따라서

https://play.golang.org/p/ZufTOzr9ig이 경우

type (
    WithKey interface { 
     key() string 
    } 

    SharedFunctionality interface { 
     WithKey 
     MethodA() string 
     MethodB() string 
    } 

    KeyHolder struct { 
     WithKey 
    } 

    FirstType struct { ... } 
    SecondType struct { ... } 
) 

func (k *KeyHolder) MethodA() string { 
    key := k.key() 
    // ... 
} 

func (k *KeyHolder) MethodB() string { 
    key := k.key() 
    // ... 
} 

func NewSharedFunctionality(w WithKey) SharedFunctionality { 
    return &KeyHolder{w} 
} 

func (ft *FirstType) key() string { ... } 
func (st *SecondType) key() string { ... } 

에서, KeyHolder 구조체가 WithKey 인터페이스를 내장하고있는 모두 FirstTypeSecondType 가지고있다).그런 다음 해당 구조체에 MethodAMethodB을 정의 할 수 있으며이 구조체는 WithKey 인터페이스 (포함하기 때문에)와 SharedFunctionality 인터페이스를 모두 포함하고 임베디드 WithKey에 의해 반환되는 키를 사용합니다. 대신 SharedFunctionality에서 다음 WithKeyFirstType 및 래핑 (자체 key(), MethodA()MethodB()을 정의하는 FirstType 의미) 말하면

, 그런 일부 (a WithKey 인터페이스)를 삽입, WithKeyFirstType 래핑 이 기본 메서드를 정의하기 위해 전적으로 존재하는 다른 구조 MethodAMethodBSharedFunctionality 인터페이스를 충족합니다.

+0

나는이 접근법을 좋아한다. 여전히 * (* NewSharedFunctionatily (firstTypeInstance)를 사용하여''.MethodA()')를 호출 할 수있을 것입니다. 그러나 얻을 수있는 최선의 것 같습니다. 나는 Dave의 접근 방식을 좋아하지만, 적어도 현재로서는이 솔루션이 나를 위해 더 잘 작동하는 것처럼 보입니다 (즉, 패키지에서 함수를 호출하는 대신 객체를 사용하여 메소드를 구현하는 것). 감사! –

2

패키지를 추출해야하는 것처럼 보입니다. 당신이 구조체로 인터페이스를 포함 할 수 있으며, 구조체는 자동으로 해당 인터페이스를 충족 : 나는 기능을 할 것이다 방법은

package keyed 

type hasKey interface { 
    Key() string 
} 

func MethodA(k hasKey) string { 
    key := k.Key() 
    // whatever 
} 

func MethodB(k hasKey) string { 
    key := k.Key() 
    // whatever 
} 

다음

package your_package 

import "keyed" 

type (
    FirstType struct { ... } 
    SecondType struct { ... } 
) 

func (ft *FirstType) Key() string { ... } 
func (st *SecondType) Key() string { ... } 

func main() { 
    first := &FirstType{} 
    second := &SecondType{} 
    keyed.MethodA(first) 
    keyed.MethodA(second) 
    keyed.MethodB(first) 
    keyed.MethodB(second) 
} 
+0

감사합니다! 그것은 상용구 코드의 양을 확실히 줄입니다. 확실히 특정 시나리오를위한 패키지를 만드는 것에 대해 생각할 것입니다. 지금 당장하고있는 구체적인 시나리오에서, Kaedys의 제안은 조금 더 좋아 보인다. 나는 그의 해결책을 받아 들일 것이다. 하지만 솔루션에 대한 감사는 매우 우아하고 유용합니다. +1! –