• Go 面向对象简明教程


    如果把 C 变成 C++, 那么 C 就消失了。

    引子

    在云原生时代,Go 变成了一门受人关注的编程语言。个人觉得,对于 Java 业务开发人员来说,熟悉一门接近系统级别的编程语言,还是有必要的。多熟悉下系统级别的原理机制,而不是局限于应用层的框架和库的使用上,对程序员来说,也是一件有益的事情。何况,谁能说,云原生不会是下一波技术浪潮呢?

    之前写过一篇, “Go语言初尝”,算是尝个鲜,现在公司开始转 Go,需要正儿八经深入学习一下。


    定义类

    Go 定义类的形式与 C 语言定义结构体很相似,连关键字 struct 都是一样的,不愧是对 C 情有独钟!

    Go 定义类:

    define.go

    
    package define
    
    type FlowResult struct {
        Code int
    }
    
    

    C 定义结构体:

    
    struct Books {
       char  title[50];
       char  author[50];
       char  subject[100];
       int   book_id;
    } book;
    
    

    注意到 Code 是首字母大写。这涉及到 Go 可见性的一条规则:

    • package A 里的首字母大写的成员变量或成员方法,对所有包可见,相当于 public 变量或方法;
    • package A 里的首字母小写的成员变量或成员方法,对 package A 之外的其它包不可见。

    比如,可以在 package main 里创建 FlowResult 的对象:

    
    package main
    
    import (
        "fmt"
        "github.com/qt/eventflow/pkg/define"
    )
    
    func testConstruct() {
        result := &define.FlowResult{ 200 }
        fmt.Println(result)
    }
    

    如果把 Code 改成 code,同样的代码会报错:

    implicit assignment of unexported field 'code' in define.FlowResult literal
    

    一般来说,写过 Java 的童鞋倾向于将字段对外不可见(private),如下:

    
    package compos
    
    type AgentDetection struct {
        eventId string
        agentId string
        osType  int
    }
    

    这时候,在 package compos 之外的其它包是无法如下面初始化的,报错同上。

    
    package main
    
    import (
        "fmt"
        "github.com/qt/eventflow/pkg/compos"
    )
    
    agent := &compos.AgentDetection{ "eventId", "agentId", 1 }
    // error : implicit assignment of unexported field 'eventId' in compos.AgentDetection literal
    

    那么,怎么创建 AgentDetection 对象呢?虽然在 package compos 外的其它包里无法如上创建,但在 package compos 里是可以这么创建的(这是 Go 提供的默认构造器)。 可以在 compos 里提供一个方法包装一下。注意到,返回值是 *AgentDetection,而赋值是 &AgentDetection。你能猜到为什么返回指针吗?

    
    package compos
    
    func (AgentDetection) Instanceof(agentId string, osType int) *AgentDetection {
        eventId := strconv.Itoa(int((time.Now().Unix()))) + strconv.Itoa(getRandomInt())
        return &AgentDetection{ eventId, agentId, osType}
    }
    

    在其它包里使用如下:

    
    package main
    
    detection := compos.AgentDetection{}.Instanceof("agentId", 1)
    fmt.Println(detection)
    

    注意,如果把 Instanceof 改成 instanceof ,就会报错:

    compos.AgentDetection{}.instanceof undefined (cannot refer to unexported field or method instanceof)
    

    默认构造器

    Java 只提供了无参的默认构造器。Go 提供了丰富的默认构造器。从上面例子可以看到,即使并没有声明一个 AgentDetection(eventId, agentId, osType),也可以直接通过 &AgentDetection{eventId, agentId, osType} 来创建一个 AgentDetection 对象。

    Go 还提供了自动的命名构造器,如下所示,仅对 agentId, osType 赋值。运行后可知,仅对 agentId, osType 赋值,而 eventId 是 空字符串。

    
    func (AgentDetection) InstanceByNaming(agentId string, osType int) *AgentDetection {
        return &AgentDetection{ agentId:agentId, osType: osType}
    }
    
    detection2 := compos.AgentDetection{}.InstanceByNaming("agentId", 1)
    fmt.Println(detection2)
    fmt.Println("eventId: " + detection2.GetEventId())
    

    空对象

    compos.AgentDetection{} 是什么含义?这会创建一个空的 AgentDetection 对象,然后用这个对象去创建一个有值的对象。

    
    empty := compos.AgentDetection{}
    fmt.Println(reflect.TypeOf(empty))   // print :  compos.AgentDetection
    

    啊,这样岂不是创建了两个对象?可以这样:

    var emp compos.AgentDetection
    demp := emp.Instanceof("agentId", 1)
    fmt.Printf("demp: %v\n", demp)
    
    fmt.Println(emp)
    fmt.Println(reflect.TypeOf(emp))
    

    咦?竟然没有出现类似 NPE 的异常?实际上,即使声明为 var emp compos.AgentDetection, emp 也并不是 nil, 而是一个空对象。猜猜下面分别打印什么 ?

    
    func testEmptyObject() {
    	var emp compos.AgentDetection
    	p1 := &emp
    	demp := emp.Instanceof("agentId", 1)
    	fmt.Printf("demp: %v\n", demp)
    	fmt.Println(emp)
    	fmt.Println(reflect.TypeOf(emp))
    
    	var emp2 compos.AgentDetection
    	p2 := &emp2
    
    	fmt.Println("compare reference to empty agentDetection")
    	compareObj(emp, emp2)
    
    
    	fmt.Println("compare pointers to empty agentDetection")
    	compareAgentDetection(p1, p2)
    
    	emp3 := &compos.AgentDetection{}
    	emp4 := &compos.AgentDetection{}
    	fmt.Println("compare pointers to empty2 agentDetection")
    	compareAgentDetection(emp3, emp4)
    }
    
    func compareObj(o1 interface{}, o2 interface{}) {
    	fmt.Printf("o1: %v\n", o1)
    	fmt.Printf("o2: %v\n", o2)
    	fmt.Printf("o1-p: %p\n", o1)
    	fmt.Printf("o2-p: %p\n", o2)
    	fmt.Printf("&o1: %v\n", &o1)
    	fmt.Printf("&o2: %v\n", &o2)
    	fmt.Printf("o1 == o2: %v\n", (o1 == o2))
    	fmt.Printf("&o1 == &o2: %v\n", &o1 == &o2)
    }
    
    func compareAgentDetection(adp1 *compos.AgentDetection, adp2 *compos.AgentDetection) {
    	fmt.Printf("adp1: %v\n", adp1)
    	fmt.Printf("adp2: %v\n", adp2)
    	fmt.Printf("adp1-p: %p\n", adp1)
    	fmt.Printf("adp2-p: %p\n", adp2)
    	fmt.Printf("*adp1: %v\n", *adp1)
    	fmt.Printf("*adp2: %v\n", *adp2)
    	fmt.Printf("&adp1: %v\n", &adp1)
    	fmt.Printf("&adp2: %v\n", &adp2)
    	fmt.Printf("adp1 == adp2: %v\n", (adp1 == adp2))
    	fmt.Printf("&adp1 == &adp2: %v\n", &adp1 == &adp2)
    	fmt.Printf("*adp1 == *adp2: %v\n", *adp1 == *adp2)
    }
    
    

    好像陷入了一个鸡生蛋还是蛋生鸡的问题。要调用 Instanceof 方法去创建一个对象,首先得有这样一个对象?其实解决这个问题的办法有两种:

    • 把 Instanceof 变成一个普通的函数,而不是 AgentDetection 的方法;
    • 将 Instanceof 变成一个工厂类 AgentDetectionFactory 的方法。

    采用第一种方式,定义一个 NewAgentDetection 可见的方法,

    
    func NewAgentDetection(agentId string, osType int) *AgentDetection {
    	eventId := strconv.Itoa(int((time.Now().Unix()))) + strconv.Itoa(getRandomInt())
    	return &AgentDetection{ eventId, agentId, osType}
    }
    
    

    然后在 package main 里就可以这样初始化:

    
    detection3 := compos.NewAgentDetection("agentId", 1)
    fmt.Printf("d3: %v\n", detection3)
    
    

    采用第二种方法,定义一个关联的工厂类 AgentDetectionFactory:

    
    type AgentDetectionFactory struct {
    }
    
    func (*AgentDetectionFactory) Instanceof(agentId string, osType int) *AgentDetection {
        eventId := strconv.Itoa(int((time.Now().Unix()))) + strconv.Itoa(getRandomInt())
        return &AgentDetection{ eventId, agentId, osType}
    }
    
    func (*AgentDetectionFactory) InstanceByNaming(agentId string, osType int) *AgentDetection {
        return &AgentDetection{ agentId:agentId, osType: osType}
    }
    
    func testFactoryMethod() {
        adf := &compos.AgentDetectionFactory{}
        detection := adf.Instanceof("agentId", 2)
        fmt.Printf( "detection from factory method: %v\n", detection)
    }
    

    单例

    像 AgentDetectionFactory 这样的类,在 Java 中是典型的单例。那么,在 Go 里怎么实现单例呢? 在网上摘抄的(DCL 思想):

    
    var (
        facLock     *sync.Mutex = &sync.Mutex{}
        adf *AgentDetectionFactory
    )
    
    func GetAgentFactoryInstance() *AgentDetectionFactory {
        if adf == nil {
            facLock.Lock()
            defer facLock.Unlock()
            if adf == nil {
                adf = &AgentDetectionFactory{}
                fmt.Println("Empty single instance...")
            }
        }
        return adf
    }
    

    做个简单的测试。猜猜下面分别打印什么 ?

    
    func testSingleton() {
    	adf := compos.GetAgentFactoryInstance()
    	adf2 := compos.GetAgentFactoryInstance()
    	compare(adf, adf2)
    }
    
    func compare(p1 *compos.AgentDetectionFactory, p2 *compos.AgentDetectionFactory) {
    	fmt.Printf("adf: %v\n", p1)
    	fmt.Printf("adf2: %v\n", p2)
    	fmt.Printf("adf-p: %p\n", p1)
    	fmt.Printf("adf2-p: %p\n", p2)
    	fmt.Printf("*adf: %v\n", *p1)
    	fmt.Printf("*adf2: %v\n", *p2)
    	fmt.Printf("&adf: %v\n", &p1)
    	fmt.Printf("&adf2: %v\n", &p2)
    	fmt.Printf("adf == adf2: %v\n", (p1 == p2))
    	fmt.Printf("&adf == &adf2: %v\n", &p1 == &p2)
    	fmt.Printf("*adf == *adf2: %v\n", *p1 == *p2)
    }
    
    

    类的方法

    实际上,前面已经给出了类的方法定义,有两种形式,如下所示:

    
    func (AgentDetection) InstanceByNaming(agentId string, osType int) *AgentDetection {
        return &AgentDetection{ agentId:agentId, osType: osType}
    }
    
    func (*AgentDetectionFactory) Instanceof(agentId string, osType int) *AgentDetection {
        eventId := strconv.Itoa(int((time.Now().Unix()))) + strconv.Itoa(getRandomInt())
        return &AgentDetection{ eventId, agentId, osType}
    }
    
    

    一个是前面不带星号的,一个是前面带星号的。有什么区别呢 ? 如果不涉及接口,看上去都是没问题的:

    
    func testClassMethod() {
        withoutStar := compos.AgentDetection{}
        ad := withoutStar.Instanceof("agentId111", 1)
        fmt.Printf("ad: %v\n", ad)
    
        withoutStar2 := &compos.AgentDetection{}
        ad2 := withoutStar2.Instanceof("agentId222", 1)
        fmt.Printf("ad: %v\n", ad2)
    
        withStar := compos.AgentDetectionFactory{}
        ad3 := withStar.Instanceof("agentId333", 1)
        fmt.Printf("ad3: %v\n", ad3)
    
        withStar2 := &compos.AgentDetectionFactory{}
        ad4 := withStar2.Instanceof("agentId444", 1)
        fmt.Printf("ad4: %v\n", ad4)
    }
    
    

    接口

    终于谈到接口了。事情稍微变得有趣了些。 接口定义也比较简单:

    
    type FlowComponent interface {
        GetName() string
        Process(context *Context) (result define.FlowResult, error error)
    }
    
    

    但类如何去实现接口呢? 这就涉及到关于接口的一个重要争论:

    • 显式地说明实现关系,比如 Java 的 implements ;
    • 实现指定的行为接口即可,比如 Go 。

    即: 如果会游泳的动物具备 CanSwim { swim() }, 那么任何 实现了 swim() 方法的类都是 CanSwim 对象,而无需显式指定与 CanSwim 的关系。CanSwim 对于谁实现了它一无所知,但是 Java 的接口可以知道谁实现了它。比如:

    
    func (hcc HostCompletionComponent) GetName() string  {
        return "compos.HostCompletionComponent"
    }
    
    func (hcc HostCompletionComponent) Process(context *Context) (result define.FlowResult, error error) {
        event := context.GetEventData()
        err := (*event).SetOsType(-1)
        if err != nil {
            return define.FlowResult{define.TERMINAL}, err
        }
        fmt.Println(*event)
        return define.FlowResult{define.CONTINUE}, nil
    }
    
    type DetectionSaver struct {
    }
    
    func (saver DetectionSaver) Process(ctx *Context) (result define.FlowResult, error error) {
        event := ctx.GetEventData()
        fmt.Printf("save detection. eventId: %s", (*event).GetEventId())
        return define.FlowResult{200}, nil
    }
    
    func (hcc DetectionSaver) GetName() string  {
        return "compos.DetectionSaver"
    }
    

    使用:

    
    // 直接赋值
    fc := &compos.HostCompletionComponent{}
    saver := &compos.DetectionSaver{}
    fc.Process(ctx)
    saver.Process(ctx)
    
    // 数组赋值
    components := [...]compos.FlowComponent{&compos.HostCompletionComponent{}, &compos.DetectionSaver{} }
    for _, comp := range components {
        res, err := comp.Process(ctx)
        if err != nil {
            fmt.Println(err)
        }
        if res.Code == define.TERMINAL {
            panic("Flow terminated")
        }
    }
    

    HostCompletionComponent, DetectionSaver 都可以做成单例的。


    完整程序

    下面是一个较为完整的小程序,基本涵盖了 Go 的常用必知必会的语言特性。

    目录结构

    eventflow-go
       cmd
          main.go
       pkg
          define
             define.go
          compos
             components.go
          yaml
             readyaml.go
       configs
          eventflow.yml
    

    define.go

    
    package define
    
    const (
        CONTINUE = 200
        TERMINAL = -1
    )
    
    type IllegalArgumentError struct {
        Msg string
        Err error
    }
    
    func (e *IllegalArgumentError) Error() string {
        return e.Msg
    }
    
    type FlowResult struct {
        Code int
    }
    
    // Do not need declared explicitly
    //func NewFlowResult(code int) FlowResult {
    //  return FlowResult{code}
    //}
    
    type EventData interface {
        GetData() interface{}
        GetType() string
        GetEventId() string
        SetOsType(i int) error
    }
    
    

    components.go

    
    package compos
    
    import (
    	"fmt"
    	"math/rand"
    	"reflect"
    	"strconv"
    	"sync"
    	"time"
    
    	"github.com/qt/eventflow/pkg/define"
    )
    
    type AgentDetection struct {
    	eventId string
    	agentId string
    	osType  int
    }
    
    func getRandomInt() int {
    	nanotime := int64(time.Now().Nanosecond())
    	rand.Seed(nanotime)
    	return rand.Int()
    }
    
    func (AgentDetection) Instanceof(agentId string, osType int) *AgentDetection {
    	eventId := strconv.Itoa(int((time.Now().Unix()))) + strconv.Itoa(getRandomInt())
    	return &AgentDetection{ eventId, agentId, osType}
    }
    
    func (AgentDetection) InstanceByNaming(agentId string, osType int) *AgentDetection {
    	return &AgentDetection{ agentId:agentId, osType: osType}
    }
    
    func NewAgentDetection(agentId string, osType int) *AgentDetection {
    	eventId := strconv.Itoa(int((time.Now().Unix()))) + strconv.Itoa(getRandomInt())
    	return &AgentDetection{ eventId, agentId, osType}
    }
    
    func (detection *AgentDetection) GetData() interface{} {
    	return detection
    }
    
    func (detection *AgentDetection) GetType() string {
    	return "Detection"
    }
    
    func (detection *AgentDetection) GetEventId() string {
    	return detection.eventId
    }
    
    func (detection *AgentDetection) GetAgentId() string {
    	return detection.agentId
    }
    
    func (detection *AgentDetection) SetOsType(osType int) (err error) {
    	if osType != 1 && osType != 2 {
    		return &define.IllegalArgumentError{"invalid parameter", nil}
    	}
    	(*detection).osType = osType
    	return nil
    }
    
    
    type AgentDetectionFactory struct {
    }
    
    func (*AgentDetectionFactory) Instanceof(agentId string, osType int) *AgentDetection {
    	eventId := strconv.Itoa(int((time.Now().Unix()))) + strconv.Itoa(getRandomInt())
    	return &AgentDetection{ eventId, agentId, osType}
    }
    
    func (*AgentDetectionFactory) InstanceByNaming(agentId string, osType int) *AgentDetection {
    	return &AgentDetection{ agentId:agentId, osType: osType}
    }
    
    var (
        facLock     *sync.Mutex = &sync.Mutex{}
        adf *AgentDetectionFactory
    )
    
    func GetAgentFactoryInstance() *AgentDetectionFactory {
    	if adf == nil {
    		facLock.Lock()
    		defer facLock.Unlock()
    		if adf == nil {
    			adf = &AgentDetectionFactory{}
    			fmt.Println("AgentDetectionFactory single instance...")
    		}
    	}
    	return adf
    }
    
    type Context struct {
    	event *define.EventData
    }
    
    func (ctx Context) New(e *define.EventData) *Context  {
    	return &Context{ e }
    }
    
    // Do not need declared explicitly
    //func NewContext(event *EventData) *Context {
    //	return &Context{event }
    //}
    
    func (ctx *Context) GetEventData() *define.EventData {
    	return ctx.event
    }
    
    const (
    	HostCompletionComponentName = iota
    	DetectionSaverName
    )
    
    type FlowComponent interface {
    	GetName() string
    	Process(context *Context) (result define.FlowResult, error error)
    }
    
    func getName(o interface{}) string  {
    	return fmt.Sprintf("%v", reflect.TypeOf(o))
    }
    
    type HostCompletionComponent struct {
    
    }
    
    func (hcc HostCompletionComponent) GetName() string  {
    	return getName(hcc)
    }
    
    func (hcc HostCompletionComponent) Process(context *Context) (result define.FlowResult, error error) {
    	event := context.GetEventData()
    	err := (*event).SetOsType(1)
    	if err != nil {
    		return define.FlowResult{define.TERMINAL}, err
    	}
    	fmt.Println(*event)
    	return define.FlowResult{define.CONTINUE}, nil
    }
    
    type DetectionSaver struct {
    }
    
    func (saver DetectionSaver) Process(ctx *Context) (result define.FlowResult, error error) {
    	event := ctx.GetEventData()
    	fmt.Printf("save detection. eventId: %s\n", (*event).GetEventId())
    	return define.FlowResult{200}, nil
    }
    
    func (saver DetectionSaver) GetName() string  {
    	return getName(saver)
    }
    
    type Empty struct {
    
    }
    
    func (Empty) Process(ctx *Context) (result define.FlowResult, error error) {
    	return define.FlowResult{200}, nil
    }
    
    func (empty Empty) GetName() string  {
    	return getName(empty)
    }
    
    var (
    	lock     *sync.Mutex = &sync.Mutex{}
    	hostComponent *HostCompletionComponent
    	detectionSaverComponent *DetectionSaver
    	empty *Empty
    	componentFactory *ComponentFactory
    )
    
    func GetHostCompletionComponentInstance() *HostCompletionComponent {
    	if hostComponent == nil {
    		lock.Lock()
    		defer lock.Unlock()
    		if hostComponent == nil {
    			hostComponent = &HostCompletionComponent{}
    			fmt.Println("HostCompletionComponent single instance...")
    		}
    	}
    	return hostComponent
    }
    
    func GetDetectionSaverComponentInstance() *DetectionSaver {
    	if detectionSaverComponent == nil {
    		lock.Lock()
    		defer lock.Unlock()
    		if detectionSaverComponent == nil {
    			detectionSaverComponent = &DetectionSaver{}
    			fmt.Println("DetectionSaver single instance...")
    		}
    	}
    	return detectionSaverComponent
    }
    
    func GetEmptyInstance() *Empty {
    	if empty == nil {
    		lock.Lock()
    		defer lock.Unlock()
    		if empty == nil {
    			empty = &Empty{}
    			fmt.Println("Empty single instance...")
    		}
    	}
    	return empty
    }
    
    type ComponentFactory struct {
    
    }
    
    func GetComponentFactoryInstance() *ComponentFactory {
    	if componentFactory == nil {
    		lock.Lock()
    		defer lock.Unlock()
    		if componentFactory == nil {
    			componentFactory = &ComponentFactory{}
    			fmt.Println("ComponentFactory single instance...")
    		}
    	}
    	return componentFactory
    }
    
    func (*ComponentFactory) Instanceof(compName int) FlowComponent {
    	switch compName {
    	case HostCompletionComponentName:
    		return GetHostCompletionComponentInstance()
    	case DetectionSaverName:
    		return GetDetectionSaverComponentInstance()
    	default:
    		return GetEmptyInstance()
    	}
    }
    
    var componentMap = map[string]FlowComponent {}
    
    func (*ComponentFactory) Init() {
    	hcc := GetHostCompletionComponentInstance()
    	componentMap[hcc.GetName()] = hcc
    	saver := GetDetectionSaverComponentInstance()
    	componentMap[saver.GetName()] = saver
    }
    
    func (*ComponentFactory) GetByName(name string) FlowComponent  {
    	return componentMap[name]
    }
    
    
    func MapValue(ints []int, f func(i int) FlowComponent) []FlowComponent  {
    	result := make([]FlowComponent, len(ints))
    	for i, v := range ints {
    		result[i] = f(v)
    	}
    	return result
    }
    
    func Exec(components []FlowComponent, ctx *Context) (err error) {
    	for _, comp := range components {
    		res, err := comp.Process(ctx)
    		if err != nil {
    			fmt.Println(err)
    			return err
    		}
    		if res.Code == define.TERMINAL {
    			panic("Flow terminated")
    		}
    	}
    	return nil
    }
    
    
    

    main.go

    
    package main
    
    import (
    	"fmt"
    	"github.com/qt/eventflow/pkg/compos"
    	"github.com/qt/eventflow/pkg/define"
    	"github.com/qt/eventflow/pkg/yaml"
    	"reflect"
    )
    
    
    func main() {
    	//testBasic()
    	testComponentExecution()
    }
    
    func testBasic() {
    	testPublicMemberConstruct()
    	testPrivateMemberConstruct()
    	testFactoryMethod()
    	testEmptyObject()
    	testSingleton()
    	testClassMethod()
    	testReadYaml()
    }
    
    func testPublicMemberConstruct() {
    	result := &define.FlowResult{ 200 }
    	fmt.Println(result)
    	fmt.Println(reflect.TypeOf(result))
    }
    
    func testPrivateMemberConstruct() {
    	//agent := &compos.AgentDetection{ "eventId", "agentId", 1 }
    	//error: implicit assignment of unexported field 'eventId' in compos.AgentDetection literal
    
    	empty := compos.AgentDetection{}
    	fmt.Println(empty)
    	fmt.Println(reflect.TypeOf(empty))
    
    	detection := compos.AgentDetection{}.Instanceof("agentId", 1)
    	fmt.Printf("d: %v\n", detection)
    
    	detection2 := compos.AgentDetection{}.InstanceByNaming("agentId", 1)
    	fmt.Printf("d2: %v\n", detection2)
    	fmt.Println("eventId: " + detection2.GetEventId())
    
    	detection3 := compos.NewAgentDetection("agentId", 1)
    	fmt.Printf("d3: %v\n", detection3)
    }
    
    func testFactoryMethod() {
    	adf := compos.GetAgentFactoryInstance()
    	detection := adf.Instanceof("agentId", 2)
    	fmt.Printf( "detection from factory method: %v\n", detection)
    }
    
    func testEmptyObject() {
    	var emp compos.AgentDetection
    	p1 := &emp
    	demp := emp.Instanceof("agentId", 1)
    	fmt.Printf("demp: %v\n", demp)
    	fmt.Println(emp)
    	fmt.Println(reflect.TypeOf(emp))
    
    	var emp2 compos.AgentDetection
    	p2 := &emp2
    
    	fmt.Println("compare reference to empty agentDetection")
    	compareObj(emp, emp2)
    
    
    	fmt.Println("compare pointers to empty agentDetection")
    	compareAgentDetection(p1, p2)
    
    	emp3 := &compos.AgentDetection{}
    	emp4 := &compos.AgentDetection{}
    	fmt.Println("compare pointers to empty2 agentDetection")
    	compareAgentDetection(emp3, emp4)
    }
    
    func compareObj(o1 interface{}, o2 interface{}) {
    	fmt.Printf("o1: %v\n", o1)
    	fmt.Printf("o2: %v\n", o2)
    	fmt.Printf("o1-p: %p\n", o1)
    	fmt.Printf("o2-p: %p\n", o2)
    	fmt.Printf("&o1: %v\n", &o1)
    	fmt.Printf("&o2: %v\n", &o2)
    	fmt.Printf("o1 == o2: %v\n", (o1 == o2))
    	fmt.Printf("&o1 == &o2: %v\n", &o1 == &o2)
    }
    
    func compareAgentDetection(adp1 *compos.AgentDetection, adp2 *compos.AgentDetection) {
    	fmt.Printf("adp1: %v\n", adp1)
    	fmt.Printf("adp2: %v\n", adp2)
    	fmt.Printf("adp1-p: %p\n", adp1)
    	fmt.Printf("adp2-p: %p\n", adp2)
    	fmt.Printf("*adp1: %v\n", *adp1)
    	fmt.Printf("*adp2: %v\n", *adp2)
    	fmt.Printf("&adp1: %v\n", &adp1)
    	fmt.Printf("&adp2: %v\n", &adp2)
    	fmt.Printf("adp1 == adp2: %v\n", (adp1 == adp2))
    	fmt.Printf("&adp1 == &adp2: %v\n", &adp1 == &adp2)
    	fmt.Printf("*adp1 == *adp2: %v\n", *adp1 == *adp2)
    }
    
    func testSingleton() {
    	adf := compos.GetAgentFactoryInstance()
    	adf2 := compos.GetAgentFactoryInstance()
    	compare(adf, adf2)
    }
    
    func compare(p1 *compos.AgentDetectionFactory, p2 *compos.AgentDetectionFactory) {
    	fmt.Printf("adf: %v\n", p1)
    	fmt.Printf("adf2: %v\n", p2)
    	fmt.Printf("adf-p: %p\n", p1)
    	fmt.Printf("adf2-p: %p\n", p2)
    	fmt.Printf("*adf: %v\n", *p1)
    	fmt.Printf("*adf2: %v\n", *p2)
    	fmt.Printf("&adf: %v\n", &p1)
    	fmt.Printf("&adf2: %v\n", &p2)
    	fmt.Printf("adf == adf2: %v\n", (p1 == p2))
    	fmt.Printf("&adf == &adf2: %v\n", &p1 == &p2)
    	fmt.Printf("*adf == *adf2: %v\n", *p1 == *p2)
    }
    
    func testClassMethod() {
    	withoutStar := compos.AgentDetection{}
    	ad := withoutStar.Instanceof("agentId111", 1)
    	fmt.Printf("ad: %v\n", ad)
    
    	withoutStar2 := &compos.AgentDetection{}
    	ad2 := withoutStar2.Instanceof("agentId222", 1)
    	fmt.Printf("ad: %v\n", ad2)
    
    	withStar := compos.AgentDetectionFactory{}
    	ad3 := withStar.Instanceof("agentId333", 1)
    	fmt.Printf("ad3: %v\n", ad3)
    
    	withStar2 := &compos.AgentDetectionFactory{}
    	ad4 := withStar2.Instanceof("agentId444", 1)
    	fmt.Printf("ad4: %v\n", ad4)
    }
    
    func testReadYaml() {
    	yaml.ReadYaml()
    }
    
    func testComponentExecution() {
    
    	//ctx := &compos.Context{ &event } //Cannot assign a value to the unexported field 'event'
    
    	detection := compos.AgentDetection{}.Instanceof("agentId", 1)
    	var event define.EventData = detection
    	ctx := compos.Context{}.New(&event)
    	cf := compos.GetComponentFactoryInstance()
    	cf.Init()
    
    	ch := make(chan int, 4)
    	defer close(ch)
    
    	go func() {
    		ch <- 0
    		ch <- 1
    		ch <- 2
    		ch <- 3
    		ch <- -1
    	}()
    
    	for {
    		select {
    		case msg := <- ch:
    			if (msg == 0) {
    				execDirect(ctx)
    			}
    			if (msg == 1) {
    				execRange(ctx)
    			}
    			if (msg == 2) {
    				execRange2(ctx, cf)
    			}
    			if (msg == 3) {
    				execByArrange(ctx, cf)
    			}
    			if (msg == -1) {
    				return
    			}
    		}
    	}
    }
    
    
    func execDirect(ctx *compos.Context) {
    	fmt.Println("execDirect")
    	fc := &compos.HostCompletionComponent{}
    	saver := &compos.DetectionSaver{}
    	fc.Process(ctx)
    	saver.Process(ctx)
    }
    
    func execRange(ctx *compos.Context)  {
    	fmt.Println("execRange")
    	components := [...]compos.FlowComponent{&compos.HostCompletionComponent{}, &compos.DetectionSaver{} }
    	for _, comp := range components {
    		res, err := comp.Process(ctx)
    		if err != nil {
    			fmt.Println(err)
    		}
    		if res.Code == define.TERMINAL {
    			panic("Flow terminated")
    		}
    	}
    }
    
    func execRange2(ctx *compos.Context, cf *compos.ComponentFactory)  {
    	fmt.Println("execRange2")
    	components := compos.MapValue([]int { compos.HostCompletionComponentName, compos.DetectionSaverName}, cf.Instanceof)
    	compos.Exec(components, ctx)
    }
    
    func execByArrange(ctx *compos.Context, cf *compos.ComponentFactory) {
    	fmt.Println("execByArrange")
    	flow := yaml.Read("./configs/eventflow.yml")
    	components := make([]compos.FlowComponent, 2)
    	for _, f := range flow.Flows {
    		fmt.Println(f.BizTypes)
    		for i, c := range f.ComponentConfigs {
    			if trueComp := cf.GetByName(c.Name) ; trueComp != nil {
    				components[i] = trueComp
    			}
    		}
    	}
    
    	compos.Exec(components, ctx)
    }
    
    

    readyaml.go

    
    package yaml
    
    import (
    	"fmt"
    	"gopkg.in/yaml.v3"
    	"io/ioutil"
    	"log"
    )
    
    type CommonConfig struct {
    	eventType string `yaml:"eventType"`
    	EventSourceType string `yaml:"eventSourceType"`
    	Model string `yaml:"model"`
    	Way string `yaml:"way"`
    	OriginParamType string `yaml:"originParamType"`
    	BuilderType string `yaml:"builderType"`
    	ComponentParamType string `yaml:"componentParamType"`
    }
    
    type ComponentConfig struct {
    	Name string   `yaml:"name"`
    }
    
    type Flow struct {
    	BizTypes         []string       `yaml:"bizTypes"`
    	CommonConfig     CommonConfig   `yaml:"commonConfig"`
    	ComponentConfigs []ComponentConfig `yaml:"componentConfigs"`
    }
    
    type EventFlow struct {
    	Version string `yaml:"version"`
    	Flows []Flow     `yaml:"flows"`
    }
    
    func Read(filename string) EventFlow {
    	ef := EventFlow{}
    
    	yamlFile, err := ioutil.ReadFile(filename)
    	if err != nil {
    		fmt.Println(err.Error())
    	}
    	//fmt.Println(string(yamlFile))
    
    	err2 := yaml.Unmarshal(yamlFile, &ef)
    	if err2 != nil {
    		log.Fatalf("error: %v", err2)
    	}
    	return ef
    }
    
    func ReadYaml() {
    
    	ef := Read("./configs/eventflow.yml")
    	fmt.Println(ef)
    	for _, f := range ef.Flows {
    		fmt.Println(f.BizTypes)
    		fmt.Println(f.CommonConfig)
    		for _, c := range f.ComponentConfigs {
    			fmt.Println(c.Name)
    		}
    	}
    }
    
    
    

    eventflow.yaml

    
    version: 1.0
    flows:
      - bizTypes:
        - 'common'
        commonConfig:
          eventType: 'create'
          eventSourceType: 'agent_event'
          model: 'EVENTFLOW'
          way: 'SERIAL'
          originParamType: 'compos.AgentDetection'
          builderType: 'compos.ContextBuilder'
          componentParamType: 'compos.Context'
        componentConfigs:
          - name: 'compos.HostCompletionComponent'
          - name: 'compos.DetectionSaver'
    
    
    
  • 相关阅读:
    诡异的命名空间问题
    如何为自定义属性提供表达式绑定支持
    为SSIS编写自定义数据流组件(DataFlow Component)之进阶篇:自定义编辑器
    SSAS : 外围应用配置器
    SSAS : 数据访问接口整理汇总
    SSAS : ADOMDConnection.ConnectionString的参数列表
    SSIS中的字符映射表转换组件
    SSAS: Discover 何处寻? 一切尽在GetSchemaDataSet
    为SSIS编写简单的同步转换组件
    如何在同步转换组件中增加输出列
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/16644915.html
Copyright © 2020-2023  润新知