Golang 시리즈 (4) 인터페이스 프로그래밍

1. 인터페이스 [멀티태스]


다중성 (polymorphisn) 은 부모 대상을 하나 이상의 자식 대상과 같은 기술로 설정할 수 있도록 하는 기술로, 값을 부여하면 부모 대상은 현재 값을 부여한 자식 대상의 특성에 따라 다른 방식으로 작동할 수 있다.
간단하게 말하면, 하위 클래스의 바늘을 부모 클래스의 바늘에 값을 부여할 수 있도록 허용하는 것이다.
즉 인용 변수가 어느 종류의 실례 대상을 가리키는지 인용 변수가 보내는 방법은 도대체 어느 종류에서 이루어지는 방법인지 프로그램이 실행되는 동안에야 결정할 수 있다.프로그램 코드를 수정하지 않으면 프로그램이 실행될 때 귀속된 구체적인 코드를 바꾸어 프로그램이 여러 개의 실행 상태를 선택할 수 있게 하는 것이 다태성이다.다태는 컴파일할 때 다태적(정적 다태적)과 운행할 때 다태적(동적 다태적)으로 나뉘는데 컴파일할 때 다태적은 일반적으로 방법으로 재부팅하고 운행할 때 다태적(동적 다태적)은 일반적으로 방법으로 재부팅하여 실현한다.

1.1 인터페이스 개념


인터페이스 유형은 유형 시스템에서 특수한 유형으로 볼 수 있는데 실례는 이 인터페이스의 구체적인 구조체 유형을 실현한 것이다.
인터페이스 유형과 이 인터페이스를 실현한 구조체 대상 간의 관계는 변수 유형과 변수 간의 관계와 같다.
인터페이스는 한 조의 방법이 정의한 집합이고 대상의 한 조의 행위를 정의하며 구체적인 유형의 실례로 구체적인 방법을 실현한다.다시 말하면 하나의 인터페이스는 정의(규범 또는 제약)이고 방법은 실현이다. 인터페이스의 역할은 정의와 실현을 분리하고 결합도를 낮추는 것이다."Reader"와 같이 "er"끝으로 이름을 지정하는 것이 습관입니다.인터페이스와 대상의 관계는 다대다. 즉, 한 대상은 여러 인터페이스를 실현할 수 있고, 한 인터페이스도 여러 대상에 의해 실현될 수 있다.
인터페이스는 Go 언어의 전체 유형 시스템의 초석이다. 다른 언어의 인터페이스는 서로 다른 구성 요소 간의 계약의 존재이고 계약의 실현에 강제적이다. 반드시 이 인터페이스를 실현했다고 명시해야 한다. 이런 인터페이스를'침입식 인터페이스'라고 부른다.Go 언어의 인터페이스는 스텔스 존재로 이 인터페이스의 모든 함수를 실현하면 이미 이 인터페이스를 실현했다는 것을 의미하며 현식 인터페이스 설명이 필요하지 않다.
  • 인터페이스의 비유
  • 너의 컴퓨터에는 USB 인터페이스가 하나밖에 없다.이 USB 인터페이스는 MP3, 디지털 카메라, 카메라, 마우스, 키보드 등을 연결할 수 있다.모든 상술한 하드웨어는 이 인터페이스를 공용할 수 있고 확장성이 좋다. 이 USB 인터페이스는 하나의 규범을 정의했다. 이 규범을 실현하기만 하면 서로 다른 장치를 컴퓨터에 접속할 수 있고 설비의 변화는 컴퓨터 자체에 아무런 영향을 주지 않는다(저결합).
  • 인터페이스 프로그래밍
  • 인터페이스는 호출자와 디자이너의 약속을 나타낸다. 여러 사람이 협력하여 같은 프로젝트를 개발할 때 서로 호출되는 인터페이스를 미리 정의하면 개발의 효율을 크게 높일 수 있다.인터페이스는 클래스로 이루어진다. 인터페이스를 실현하는 클래스는 반드시 인터페이스의 성명에 따라 인터페이스가 제공하는 모든 기능을 엄격히 실현해야 한다.인터페이스가 있으면 기존 인터페이스 성명에 영향을 주지 않는 상황에서 인터페이스의 내부 실현을 수정하여 호환성 문제를 최소화할 수 있다.
    인터페이스 프로그래밍은 세 가지 측면으로 나눌 수 있는데 그것이 바로 제정자(또는 조율자), 실현자(또는 생산자), 호출자(또는 소비자)이다.
    다른 디자이너가 인터페이스를 호출한 후에 인터페이스의 정의를 함부로 변경할 수 없다. 그렇지 않으면 프로젝트 개발자의 사전 약속은 의미를 잃게 된다.그러나 클래스에서 해당하는 코드를 수정하여 변경해야 할 내용을 완성할 수 있다.

    1.2 비침입 인터페이스


    비침입식 인터페이스: 하나의 클래스는 인터페이스가 요구하는 모든 함수만 실현하면 이 인터페이스를 실현하고 현식 성명이 필요하지 않다는 것을 나타낸다
    type File struct{
      // 
    }
    //File 
    func (f *File) Read(buf []byte) (n int,err error)
    func (f *File) Write(buf []byte) (n int,err error)
    func (f *File) Seek(off int64,whence int) (pos int64,err error)
    func (f *File) Close() error
    // 1:IFile
    type IFile interface{
      Read(buf []byte) (n int,err error)
      Write(buf []byte) (n int,err error)
      Seek(off int64,whence int) (pos int64,err error)
      Close() error
    }
    // 2:IReader
    type IReader interface{
      Read(buf []byte) (n int,err error)
    }
    // ,File IFile IReader , 
    var file1 IFile = new(File)
    var file2 IReader = new(File)

    1.3 인터페이스 할당


    클래스가 이 인터페이스의 모든 방법을 실현하기만 하면 이 클래스를 이 인터페이스에 할당할 수 있으며 인터페이스는 주로 다태화 방법에 사용된다.즉 인터페이스에 대한 정의 방법, 서로 다른 실현 방식이다.
    인터페이스에 값을 부여합니다: 1) 인터페이스에 대상을 실례적으로 값을 부여합니다
    type IUSB interface{
        // IUSB 
    }
    // , , , 
    type MP3 struct{
        // IUSB , MP3 
    }
    type Mouse struct{
        // IUSB , Mouse 
    }
    // MP3
    var usb IUSB =new(MP3)
    usb.Connect()
    usb.Close()
    // Mouse
    var usb IUSB =new(Mouse)
    usb.Connect()
    usb.Close()

    2) 인터페이스를 다른 인터페이스에 할당
  • 두 인터페이스가 같은 방법 목록을 가지면(순서와 무관), 즉 두 인터페이스가 서로 값을 부여할 수 있다
  • 인터페이스 값만 인터페이스 A의 방법 목록이 인터페이스 B의 서브집합(즉 인터페이스 A에 정의된 모든 방법이 인터페이스 B에 정의되어 있다고 가정)이면 B 인터페이스의 실례는 A의 대상에게 값을 부여할 수 있다.반대로 성립되지 않는다. 즉, 하위 인터페이스 B는 아버지 인터페이스 A를 포함하기 때문에 하위 인터페이스의 실례를 아버지 인터페이스에 부여할 수 있다.
  • 즉 서브인터페이스 실례는 서브인터페이스의 모든 방법을 실현했고 부인터페이스의 방법 목록은 서브인터페이스의 서브집합이다. 그러면 서브인터페이스 실례는 부인터페이스의 모든 방법을 자연스럽게 실현했기 때문에 서브인터페이스 실례를 부인터페이스에 값을 부여할 수 있다.
  • type Writer interface{    // 
        Write(buf []byte) (n int,err error)
    }
    type ReadWriter interface{    // 
        Read(buf []byte) (n int,err error)
        Write(buf []byte) (n int,err error)
    }
    var file1 ReadWriter=new(File)   // 
    var file2 Writer=file1           // 

    1.4 인터페이스 쿼리


    switch 밖에서 하나의 인터페이스 유형이 어떤 인터페이스를 실현했는지 판단하려면 '쉼표 ok' 를 사용할 수 있습니다.
    value, ok := Interfacevariable.(implementType)
    그 중에서Interfacevariable는 인터페이스 변수(인터페이스 값)이고implementType은 이 인터페이스의 유형을 실현하기 위해value는 인터페이스 변수의 실제 유형 변수의 값을 되돌려줍니다. 만약에 이 유형이 이 인터페이스가true를 되돌려준다면value는 인터페이스 변수의 실제 유형 변수를 되돌려줍니다.
    // file1 File 
    var file1 Writer=...
    if file5,ok:=file1.(File);ok{  
      ...
    }

    1.5 인터페이스 유형 쿼리


    Go에서 인터페이스 값에 전달되는 변수 유형을 판단하려면 type switch를 사용하여 얻을 수 있습니다.(type)는 switch에서만 사용할 수 있습니다.
    //   I   R  
    type R struct { i int }
    func (p *R) Get() int { return p.i }
    func (p *R) Put(v int) { p.i = v }
    
    func f(p I) {
        switch t := p.(type) { //   p  
            case *S: //   S  
            case *R: //   R  
            case S:  // S  
            case R:  // R  
            default: //  I  
        }
    }

    1.6 인터페이스 조합

    // , , 
    type ReadWriter interface{  // , 
      Reader      // Reader
      Writer      // Writer
    }

    1.7 Any 유형 [빈 인터페이스]


    모든 종류가 빈 인터페이스에 일치합니다:interface {}.빈 인터페이스 형식은 방법에 대한 제약이 없습니다. (방법이 없기 때문에) 임의의 형식을 포함할 수도 있고 다른 인터페이스 형식으로 전환할 수도 있습니다.이 인터페이스에 전달된 유형 변수가 변환된 인터페이스를 실현하면 정상적으로 실행할 수 있으며, 그렇지 않으면 실행 중 오류가 발생합니다.
    //interface{} Any , Java Object 
    var v1 interface{}=struct{X int}{1}
    var v2 interface{}="abc"
    
    func DoSomething(v interface{}) {   // , 
       // ...
    }

    1.8 인터페이스 코드 예

    // animal
    type Animal interface {
        Speak() string
    }
    //Dog animal 
    type Dog struct {
    }
    
    func (d Dog) Speak() string {
        return "Woof!"
    }
    //Cat animal 
    type Cat struct {
    }
    
    func (c Cat) Speak() string {
        return "Meow!"
    }
    //Llama animal 
    type Llama struct {
    }
    
    func (l Llama) Speak() string {
        return "?????"
    }
    //JavaProgrammer animal 
    type JavaProgrammer struct {
    }
    
    func (j JavaProgrammer) Speak() string {
        return "Design patterns!"
    }
    // 
    func main() {
        animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}  // 
        for _, animal := range animals {
            fmt.Println(animal.Speak())  // 
        }
    }

    2.client-go에서 인터페이스의 사용 분석


    다음은 k8s.io/client-go/kubernetes/typed/core/v1/pod.go의pod 대상으로 분석한다.

    2.1 인터페이스 설계 및 정의


    2.1.1 인터페이스 조합

    // PodsGetter has a method to return a PodInterface.
    // A group's client should implement this interface.
    type PodsGetter interface {
        Pods(namespace string) PodInterface
    }

    2.1.2 인터페이스 정의

    // PodInterface has methods to work with Pod resources.
    type PodInterface interface {
        Create(*v1.Pod) (*v1.Pod, error)
        Update(*v1.Pod) (*v1.Pod, error)
        UpdateStatus(*v1.Pod) (*v1.Pod, error)
        Delete(name string, options *meta_v1.DeleteOptions) error
        DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error
        Get(name string, options meta_v1.GetOptions) (*v1.Pod, error)
        List(opts meta_v1.ListOptions) (*v1.PodList, error)
        Watch(opts meta_v1.ListOptions) (watch.Interface, error)
        Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Pod, err error)
        PodExpansion
    }
    PodInterface 인터페이스는pod 대상이 사용하는 방법을 정의했고 일반적으로 삭제 및 수정 등이다.다른kubernetes 자원 대상의 인터페이스 정의는 유사한데, 차이점은 참여 대상과 참여 대상이 관련이 있다는 것이다.예를 들어 Create(*v1.Pod) (*v1.Pod, error) 방법이 정의한 입참출참은 *v1.Pod이다.이 인터페이스를 실현하려면, 이 인터페이스를 실현하는 모든 방법이다.

    2.2 인터페이스의 실현


    2.2.1 구조체의 정의

    // pods implements PodInterface
    type pods struct {
        client rest.Interface
        ns     string
    }

    2.2.2 new 함수 [구조 함수]

    // newPods returns a Pods
    func newPods(c *CoreV1Client, namespace string) *pods {
        return &pods{
            client: c.RESTClient(),
            ns:     namespace,
        }
    }

    2.2.3 방법의 실현


    Get
    // Get takes name of the pod, and returns the corresponding pod object, and an error if there is any.
    func (c *pods) Get(name string, options meta_v1.GetOptions) (result *v1.Pod, err error) {
        result = &v1.Pod{}
        err = c.client.Get().
            Namespace(c.ns).
            Resource("pods").
            Name(name).
            VersionedParams(&options, scheme.ParameterCodec).
            Do().
            Into(result)
        return
    }

    List
    // List takes label and field selectors, and returns the list of Pods that match those selectors.
    func (c *pods) List(opts meta_v1.ListOptions) (result *v1.PodList, err error) {
        result = &v1.PodList{}
        err = c.client.Get().
            Namespace(c.ns).
            Resource("pods").
            VersionedParams(&opts, scheme.ParameterCodec).
            Do().
            Into(result)
        return
    }

    Create
    // Create takes the representation of a pod and creates it.  Returns the server's representation of the pod, and an error, if there is any.
    func (c *pods) Create(pod *v1.Pod) (result *v1.Pod, err error) {
        result = &v1.Pod{}
        err = c.client.Post().
            Namespace(c.ns).
            Resource("pods").
            Body(pod).
            Do().
            Into(result)
        return
    }

    Update
    // Update takes the representation of a pod and updates it. Returns the server's representation of the pod, and an error, if there is any.
    func (c *pods) Update(pod *v1.Pod) (result *v1.Pod, err error) {
        result = &v1.Pod{}
        err = c.client.Put().
            Namespace(c.ns).
            Resource("pods").
            Name(pod.Name).
            Body(pod).
            Do().
            Into(result)
        return
    }

    Delete
    // Delete takes name of the pod and deletes it. Returns an error if one occurs.
    func (c *pods) Delete(name string, options *meta_v1.DeleteOptions) error {
        return c.client.Delete().
            Namespace(c.ns).
            Resource("pods").
            Name(name).
            Body(options).
            Do().
            Error()
    }

    2.3 인터페이스 호출


    예:
    //  clientset 
    clientset, err := kubernetes.NewForConfig(config)
    //  
    pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})

    clientset은 인터페이스Interface를 실현했고 Interface는 인터페이스 조합으로 각각의 client의 인터페이스 유형을 포함한다.예를 들어CoreV1() 방법에 대응하는 인터페이스 유형은CoreV1Interface이다.
    다음은 clientset의 CoreV1() 방법으로 이루어진 것이다.
    // CoreV1 retrieves the CoreV1Client
    func (c *Clientset) CoreV1() corev1.CoreV1Interface {
        return c.coreV1
    }

    이 방법은 하나 로 이해할 수 있다.구조 함수의 반환값 유형은 인터페이스 유형CoreV1Interface이고return의 반환값은 이 인터페이스 유형의 구조체 대상c.coreV1을 실현했다.
    인터페이스 유형은 특수한 유형으로 인터페이스 유형과 구조체 대상 간의 관계는 변수 유형과 변수 간의 관계와 같다.그 중의 구조체 대상은 반드시 이 인터페이스 유형의 모든 방법을 실현해야 한다.
    그래서clientset의 CoreV1() 방법은 하나의 CoreV1Client 구조체 대상을 되돌려주는 것이다.이 구조체의 대상은 CoreV1Interface 인터페이스를 실현했고 이 인터페이스도 하나의 인터페이스 조합이다.
    type CoreV1Interface interface {
        RESTClient() rest.Interface
        ComponentStatusesGetter
        ConfigMapsGetter
        EndpointsGetter
        EventsGetter
        LimitRangesGetter
        NamespacesGetter
        NodesGetter
        PersistentVolumesGetter
        PersistentVolumeClaimsGetter
        PodsGetter
        PodTemplatesGetter
        ReplicationControllersGetter
        ResourceQuotasGetter
        SecretsGetter
        ServicesGetter
        ServiceAccountsGetter
    }

    실현된Pods() 방법은 그중의PodsGetter 인터페이스이다.Pods()CoreV1()와 같은 구조 함수이고 구조 함수의 반환값 유형은 PodInterface 인터페이스이고 반환값은 PodInterface 인터페이스를 실현한 pods 구조체 대상이다.
    func (c *CoreV1Client) Pods(namespace string) PodInterface {
        return newPods(c, namespace)
    }

    한편, PodInterface 인터페이스 정의는 인터페이스 정의를 참고하고 pods 대상은 PodInterface 인터페이스의 방법을 실현했으며 구체적인 인터페이스 실현을 참고했다.
    최종적으로 pods 대상의 List() 방법을 호출했다.
    pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})

    즉 상기 코드는 특정한 인터페이스를 실현한 구조체 대상의 구조 함수를 끊임없이 호출하여 구체적인 구조체 대상을 생성하고 구조체 대상의 특정한 방법을 다시 호출하는 것이다.

    3. 유니버설 인터페이스 디자인


    3.1 인터페이스 정의

    // ProjectManager manage life cycle of Deployment and Resources
    type PodInterface interface {
        Create(*v1.Pod) (*v1.Pod, error)
        Update(*v1.Pod) (*v1.Pod, error)
        UpdateStatus(*v1.Pod) (*v1.Pod, error)
        Delete(name string, options *meta_v1.DeleteOptions) error
        DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error
        Get(name string, options meta_v1.GetOptions) (*v1.Pod, error)
        List(opts meta_v1.ListOptions) (*v1.PodList, error)
        Watch(opts meta_v1.ListOptions) (watch.Interface, error)
        Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Pod, err error)
        PodExpansion
    }

    3.2 구조체 정의

    // pods implements PodInterface
    type pods struct {
        client rest.Interface
        ns     string
    }

    3.3 구조 함수

    // newPods returns a Pods
    func newPods(c *CoreV1Client, namespace string) *pods {
        return &pods{
            client: c.RESTClient(),
            ns:     namespace,
        }
    }

    3.4 구조체 실현


    List()
    // List takes label and field selectors, and returns the list of Pods that match those selectors.
    func (c *pods) List(opts meta_v1.ListOptions) (result *v1.PodList, err error) {
        result = &v1.PodList{}
        err = c.client.Get().
            Namespace(c.ns).
            Resource("pods").
            VersionedParams(&opts, scheme.ParameterCodec).
            Do().
            Into(result)
        return
    }

    3.5 인터페이스 호출

    pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})

    3.6 기타 인터페이스 설계 예

    type XxxManager interface {
        Create(args argsType) (*XxxStruct, error)
        Get(args argsType) (**XxxStruct, error)
        Update(args argsType) (*XxxStruct, error)
        Delete(name string, options *DeleleOptions) error
    }
    
    type XxxManagerImpl struct {
        Name string
        Namespace string
        kubeCli *kubernetes.Clientset
    }
    
    func NewXxxManagerImpl (namespace, name string, kubeCli *kubernetes.Clientset) XxxManager {
        return &XxxManagerImpl{
            Name name,
            Namespace namespace,
            kubeCli: kubeCli,
        }
    }
    
    func (xm *XxxManagerImpl) Create(args argsType) (*XxxStruct, error) {
        // 
    }

    좋은 웹페이지 즐겨찾기