栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Go语言面向对象之旅

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Go语言面向对象之旅

目的:

通过一道题目体验下Go语言下的OO编程范式。

题目:

模拟人和机器人制造产品。

这里人和机器人在工作时都是一名worker(扮演的角色),工作的流程是一样的:如果能量没有消耗完,那么可以继续制造产品,否则停工。

区别在于依赖的能量消耗和获取方式不同:

    人制造产品会消耗吃饭得到的能量,缺乏能量后需要再吃饭补充。人吃完饭后能量值为10,每生产一件产品,消耗能量值为1,吃完饭后能量恢复到10。机器人制造产品会消耗电能,缺乏能量后需要再充电,充完电可以继续工作。充完电后能量值为100,每生产一件产品,消耗能量值为1,充电后能量值恢复到100。

基于组合式设计思想,得到一个领域模型:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HykebIFT-1645663259864)(https://upload-images.jianshu.io/upload_images/2463211-33dd36fe2be15f24.png?imageMogr2/auto-orient/strip|imageView2/2/format/webp)]

Energy:

接口在Golang中是一个interface。它包含两个方法:一个是消耗能量Consume,另一个是能量是否耗尽IsExhausted。

package energy

type Energy interface {
	Consume()
	IsExhausted() bool
}

关于接口可以参考:Go 专栏|接口 interface - 简书 (jianshu.com)。

HumanEnergy:

基于C++的知识可以将HumanEnergy理解为是类Energy的子类。

package energy

const MAX_CONSUME_TIMES int = 10

type HumanEnergy struct {
	isHungry     bool
	consumeTimes int
}

func (this *HumanEnergy) Eat() {
	this.consumeTimes = 0
	this.isHungry = false
}

func (this *HumanEnergy) Consume() {
	this.consumeTimes++
	if this.consumeTimes >= MAX_CONSUME_TIMES {
		this.isHungry = true
	}
}

func (this *HumanEnergy) IsExhausted() bool {
	return this.isHungry
}

基础语法参考:Go 语言函数方法 | 菜鸟教程 (runoob.com)

RobotEnergy:

同样地,RobotEnergy也是Energy的子类

package energy

const (
	FULL_PERCENT    int = 100
	CONSUME_PERCENT int = 1
)

type RobotEnergy struct {
	percent int
}

func (this *RobotEnergy) Charge() {
	this.percent = FULL_PERCENT
}

func (this *RobotEnergy) Consume() {
	if this.percent > 0 {
		this.percent -= CONSUME_PERCENT
	}
}

func (this *RobotEnergy) IsExhausted() bool {
	return this.percent == 0
}

Worker:

Worker依赖于Energy这个接口,具体这个接口实际上是指向HumanEnergy还是RobotEnergy,根据需要注入。

这里体现的是依赖倒置原则:

Worker依赖于Energy这个稳定接口,在Produce产品的时候不关心用的能量是HumanEnergy还是RobotEnergy。

package worker

import "github.com/yanxicheung/energy/energy"

type Worker struct {
	producerNum int
	Energy      energy.Energy
}

func (this *Worker) Produce() {
	if this.Energy.IsExhausted() {
		return
	}
	this.producerNum++
	this.Energy.Consume()
}

func (this *Worker) GetProduceNum() int {
	return this.producerNum
}

Object:

领域对象是对具体Energy和Worker的组合。

这里会介绍两种组合方式:

第一种是Human采用的委托方式,相当于C++中的包含。

第二种是Robot采用的匿名组合,相当于C++中的继承。

Human:

Human领域对象组合了HumanEnergy和Worker。代码如下:

package object

import (
	"github.com/yanxicheung/energy/energy"
	"github.com/yanxicheung/energy/worker"
)

type Human struct {
    // 委托方式
	Energy energy.HumanEnergy
	Worker worker.Worker
}

// 函数名字小写,包外不可见;
func (this *Human) inject() {
	this.Worker.Energy = &this.Energy
}

func NewHuman() *Human {
	h := &Human{}
	h.inject()
	return h
}

this.Worker.Energy = &this.Energy的作用是依赖注入,将Worker依赖的接口Energy实际指向HumanEnergy。

由于 Human 使用了委托方式组合了HumanEnergy和Worker。 所以Human并没有实现Energy的抽象接口,所以this不可以直接赋值给this.Worker.Energy,否则编译报错:InvalidIfaceAssign。

Robot:

Robot领域对象组合了RobotEnergy和Worker。代码如下:

package object

import (
	"github.com/yanxicheung/energy/energy"
	"github.com/yanxicheung/energy/worker"
)

type Robot struct {
	// 匿名组合struct 相当与C++中的继承
	energy.RobotEnergy
	worker.Worker
}

func (this *Robot) inject() {
	this.Worker.Energy = this
}

func NewRobot() *Robot {
	r := &Robot{}
	r.inject()
	return r
}

this.Worker.Energy = this的作用是依赖注入,将Worker依赖的接口Energy实际指向robotEnergy。

由于 Robot 使用了匿名组合方式组合了RobotEnergy和Worker。 所以Robot实现Energy的抽象接口,所以this可以直接赋值给this.Worker.Energy。

使用:

Human领域对象的具体使用如下:

func HumanWork() {
	human := object.NewHuman()
	human.Energy.Eat()
	for {
		if human.Energy.IsExhausted() {
			break
		}
		human.Worker.Produce()
	}
	fmt.Printf("human produce %v products in one cyclen", human.Worker.GetProduceNum())
}

由于Robot使用匿名组合方式组合了RobotEnergy和Worker,当我们访问该struct的方法时,可以通过默认的变量名访问:

func RobotWork() {
	robot := object.NewRobot()
	robot.RobotEnergy.Charge()
	for {
		if robot.Energy.IsExhausted() {
			break
		}
		robot.Worker.Produce()
	}
	fmt.Printf("robot produce %v products in one cyclen", robot.Worker.GetProduceNum())
}

也可以直接访问(略去默认的变量名) :

func RobotWork() {
	robot := object.NewRobot()
	robot.Charge()
	for {
		if robot.IsExhausted() {
			break
		}
		robot.Produce()
	}
	fmt.Printf("robot produce %v products in one cyclen", robot.GetProduceNum())
}

参考文献:
    Implement Domain Object in Golang - 简书 (jianshu.com)Golang中小类大对象的一种实现 - 简书 (jianshu.com)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/744524.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号