Golang에서 디자인 패턴 "Command"를 배웁니다.

16578 단어 5디자인 패턴GoF
GoF의 디자인 패턴을 Golang에서 학습하고 싶습니다.
이번에는 Qiita 기사 : "파이썬에서 디자인 패턴 "Command"를 배우십시오."에서 다룬 Python 기반의 "Command"샘플 앱을 Golang에서 다시 구현해 보았습니다.

■ Command(명령 패턴)



Command 패턴(영문: command pattern)은 객체 지향 프로그래밍에 있어서의 디자인 패턴의 하나로, 동작을 표현하는 객체를 나타낸다. Command 오브젝트는, 동작과 거기에 수반하는 파라미터를 캡슐화한 것이다.
예로서, 인쇄를 실시하는 라이브러리가 PrintJob 클래스를 갖추고 있다고 한다. 라이브러리의 유저는 새롭게 PrintJob 오브젝트를 작성해, 파라미터 (인쇄하는 문서, 인쇄 부수 등)를 세트 해, 마지막에 프린터에 작업을 송신하는 메소드를 호출한다.

UML class and sequence diagram





UML 클래스 diagram




(이상 위키피디아(Wikipedia)에서 인용)

■ "Command" 샘플 프로그램



실제로 Command 패턴을 활용한 샘플 프로그램을 움직여서 다음과 같은 동작의 모습을 확인하고 싶습니다.
  • 파일 권한 "777"test1.txt 파일 만들기
  • 파일 권한 "600"test2.txt 파일 만들기

  • 또한, 샘플 프로그램은, 제1 인수: 작성하고 싶은 파일명, 제2 인수: 부여하고 싶은 파일 권한으로 합니다.
    $ go run Main.go test1.txt 777
    % touch test1.txt
    % chmod 777 test1.txt
    
    $ go run Main.go test2.txt 600
    % touch test2.txt
    % chmod 600 test2.txt
    

    파일 목록을 확인합니다.
    $ ls -l|grep test
    -rwxrwxrwx  1 ttsubo  staff    0  3 29 05:28 test1.txt
    -rw-------  1 ttsubo  staff    0  3 29 05:29 test2.txt
    

    예상대로 파일을 생성할 수 있었습니다.

    ■ 샘플 프로그램에 대해 자세히 알아보기



    Git 저장소에도 비슷한 코드가 있습니다.
    htps : // 기주 b. 코 m / 츠 츠보 / s dy _ f_로 shin gan_pate rn_uh th_go g / t ree /
  • 디렉토리 구성
  • .
    ├── Main.go
    └── command
        └── command.go
    

    (1) Command(명령)의 역할



    명령의 인터페이스를 정하는 역할입니다.
    샘플 프로그램에서는, command 인터페이스가, 이 역할을 노력합니다.

    command/command.go
    package command
    
    import (
        "fmt"
        "os"
    )
    
    type command interface {
        execute()
        display()
    }
    

    (2) ConcreteCommand(구체적 명령)의 역할


    Command 역할의 인터페이스를 실제로 구현하고 있는 역할입니다.
    샘플 프로그램에서는, FileTouchCommand 구조체와 ChmodCommand 구조체가, 이 역할을 노력합니다.

    command/command.go
    // FileTouchCommand is struct
    type FileTouchCommand struct {
        filename string
        receiver *FileOperator
    }
    
    // NewFileTouchCommand func for initializing FileTouchCommand
    func NewFileTouchCommand(filename string, receiverObj *FileOperator) *FileTouchCommand {
        return &FileTouchCommand{
            filename: filename,
            receiver: receiverObj,
        }
    }
    
    func (f *FileTouchCommand) execute() {
        f.receiver.createFile(f.filename)
    }
    
    func (f *FileTouchCommand) display() {
        fmt.Printf("%% touch %s\n", f.filename)
    }
    

    command/command.go
    // ChmodCommand is struct
    type ChmodCommand struct {
        filename   string
        permission uint64
        receiver   *FileOperator
    }
    
    // NewChmodCommand func for initializing ChmodCommand
    func NewChmodCommand(filename string, permission uint64, receiverObj *FileOperator) *ChmodCommand {
        return &ChmodCommand{
            filename:   filename,
            permission: permission,
            receiver:   receiverObj,
        }
    }
    
    func (c *ChmodCommand) execute() {
        c.receiver.changeFileMode(c.filename, c.permission)
    }
    
    func (c *ChmodCommand) display() {
        fmt.Printf("%% chmod %o %s\n", c.permission, c.filename)
    }
    

    (3) Receiver(수신자)의 역할


    ConcreteCommand 역할 명령을 실행할 때 적용되는 역할입니다. 명령의 수령인이라고 부를 수 있습니다.
    샘플 프로그램에서는, FileOperator 구조체가, 이 역할을 노력합니다.

    command/command.go
    // FileOperator is struct
    type FileOperator struct {
    }
    
    // NewFileOperator func for initializing FileOperator
    func NewFileOperator() *FileOperator {
        return &FileOperator{}
    }
    
    func (f *FileOperator) createFile(filename string) {
        os.Create(filename)
    }
    
    func (f *FileOperator) changeFileMode(filename string, permission uint64) {
        os.Chmod(filename, os.FileMode(permission))
    }
    

    (4) Invoker(기동자)의 역할



    명령 실행을 시작하는 역할입니다. Command 역할에 정의되어 있는 인터페이스를 호출하는 역할이 됩니다.
    샘플 프로그램에서는, CompositeCommand 구조체가, 이 역할을 노력합니다.

    command/command.go
    // CompositeCommand is struct
    type CompositeCommand struct {
        cmds []command
    }
    
    //NewCompositeCommand func for initializing CompositeCommand
    func NewCompositeCommand() *CompositeCommand {
        return &CompositeCommand{}
    }
    
    // AppendCmd func for appending command
    func (c *CompositeCommand) AppendCmd(cmd command) {
        c.cmds = append(c.cmds, cmd)
    }
    
    // Execute func for executing command
    func (c *CompositeCommand) Execute() {
        for _, cmd := range c.cmds {
            cmd.execute()
        }
    }
    

    (5) Client(의뢰인)의 역할


    ConcreteCommand 역을 생성해, 그 때 Receiver 역을 할당하는 역입니다.
    샘플 프로그램에서는 startMain 함수가 이 역할을 합니다.

    Main.go
    package main
    
    import (
        "flag"
        "strconv"
    
        "./command"
    )
    
    func startMain(filename string, permission uint64) {
        recv := command.NewFileOperator()
        cc := command.NewCompositeCommand()
        cc.AppendCmd(command.NewFileTouchCommand(filename, recv))
        cc.AppendCmd(command.NewChmodCommand(filename, permission, recv))
        cc.Execute()
        cc.Display()
    }
    
    func main() {
        flag.Parse()
        perm32, _ := strconv.ParseUint(flag.Arg(1), 8, 32)
        startMain(flag.Arg(0), perm32)
    }
    

    ■ 참고 URL


  • 파이썬에서 디자인 패턴 "Command"를 배우십시오.
  • 좋은 웹페이지 즐겨찾기