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'


posted @ 2022-08-31 23:15  琴水玉  阅读(126)  评论(0编辑  收藏  举报