6

Goでテンプレートメソッドパターンを実装するエレガントな正規の方法はありますか? C++ では、これは次のようになります。

#include <iostream>
#include <memory>

class Runner {
public:
    void Start() {
        // some prepare stuff...
        Run();
    }
private:
    virtual void Run() = 0;
};

class Logger : public Runner {
private:
    virtual void Run() override {
        std::cout << "Running..." << std::endl;
    }
};

int main() {
    std::unique_ptr<Runner> l = std::make_unique<Logger>();
    l->Start();
    return 0;
}

golangで私は次のようなものを書きました:

package main

import (
    "fmt"
    "time"
)

type Runner struct {
    doRun func()
    needStop bool
}

func (r *Runner) Start() {
    go r.doRun()
}

func NewRunner(f func()) *Runner {
    return &Runner{f, false}
}

type Logger struct {
    *Runner
    i int
}

func NewLogger() *Logger {
    l := &Logger{}
    l.doRun = l.doRunImpl
    return l
}

func (l *Logger) doRunImpl() {
    time.Sleep(1 * time.Second)
    fmt.Println("Running")
}

func main() {
    l := NewLogger()
    l.Start()
    fmt.Println("Hello, playground")
}

しかし、このコードは実行時のヌル ポインター エラーで失敗します。基本的な考え方は、派生クラス (go 構造体) から基本クラス ルーチンにいくつかの機能を組み合わせて、この mix-in 派生ルーチンから基本クラスの状態を利用できるようにすることです。

4

3 に答える 3

3

テンプレート メソッド デザイン パターンを Golang で機能させるための鍵は、埋め込み機能関数割り当てを適切に使用することです。

以下は、期待どおりに動作するコード スニペットです。

package main

import (
    "fmt"
)

type Runner struct {
    run func()  // 1. this has to get assigned the actual implementation
}

func NewRunner(i func()) *Runner {
    return &Runner{i}
}

func (r *Runner) Start() {
    r.run()
}

type Logger struct {
    Runner
}

func NewLogger() *Logger {
    l := Logger{}
    l.run = l.loggerRun  // 2. the actual version is assigned
    return &l
}

func (l *Logger) loggerRun() {
    fmt.Println("Logger is running...")
}

func main() {
    l := NewLogger()  // 3. constructor should be used, to get the assignment working
    l.Start()
}

タイプ Runner はfunc()、特定のサブタイプに従って、実際の実装を受け取ることになっている属性を定義します。Start()への呼び出しをラップrun()し、正しいレシーバー (ベース レシーバー) で呼び出されると、正しいバージョンの を実行できますrun()。これは、コンストラクターで発生します (つまりNewLogger()、メソッドの実際のバージョンが埋め込みrun()の属性に割り当てられます)。runタイプ。

そして、出力は次のとおりです。

Logger is running...

Program exited.

ここでコードを実行し、変更して、この設計パターンの他のバリエーションをテストできます。

于 2016-10-16T16:52:28.350 に答える