用 Go 语言实现直线,射线,线段的实例程序,并满足 SRP,OCP 设计原则。

要求:用 Go 语言实现直线,射线,线段的实例程序,并满足 SRP,OCP 设计原则。

一. 接口设计

  1. Oner 接口,也是该程序最核心的接口

    type Oner interface {
    	isOn(p Point) bool
    }
    
  2. Pointer 接口,实现该接口可以返回点的 x 和 y 的值

    type Pointer interface {
    	//获取点的x坐标
    	getX() float64
    	//获取点的y坐标
    	getY() float64
    }
    
  3. Linear 接口,计算斜率,直线截距,返回两点对象

    type Linear interface {
    	//计算直线斜率
    	getSlope () float64
    	//计算直线截距
    	getIntercept () float64
    	//获取点A
    	getA () Point
    	//获取点B
    	getB () Point
    }
    
  4. LineSegment 接口,获取线段长度,判断给定点是否在线段上

    type LineSegment interface {
    	//同样需要实现Oner接口,判断是否在线段上
    	Oner
    	//获取线段长度
    	getLength() float64
    }
    

二. 数据类型设计

  1. Point 类型,x 和 y 属性分别代表 x 轴和 y 轴的值,需要实现 Pointer 接口
    type Point struct {
    	x float64
    	y float64
    }
    
  2. LinearObject 类型,a 和 b 为给定的两点,数据类型为 Point,需要实现 Linear 接口
    type LinearObject struct {
    	//默认a点的x值小于b点的x值
    	a Point
    	b Point
    }
    
  3. LineSegmentObject 类型,需要实现 LineSegment 接口
    type LineSegmentObject struct {
    	//持有LinearObject对象
    	ls_lo LinearObject
    }
    
  4. Ray 类型,需要实现 Oner 接口
    type Ray struct {
    	r_lo LinearObject
    }
    
  5. Line 类型,需要实现 Oner 接口
    type Line struct {
    	l_lo LinearObject
    }
    

三. 接口实现,实现接口中所有方法即实现了该接口

  1. Ponit 类型实现 Pointer 接口

    func (p Point) getX() float64 {
    	return p.x
    }
    
    func (p Point) getY() float64 {
    	return p.y
    }
    
  2. LinearObject 类型实现 Linear 接口

    //计算斜率
    func (lo LinearObject) getSlope() float64 {
    	var slop float64
    	if lo.a.getX() == lo.b.getY() {
    		slop = 1
    	} else {
    		slop = (lo.a.getY() - lo.b.getY()) / (lo.a.getX() - lo.b.getX())
    	}
    	return slop
    }
    
    //计算直线截距
    func (lo LinearObject) getIntercept() float64 {
    	var intercept float64
    	if lo.getSlope() == 1 {
    		intercept = 0
    	} else {
    		intercept = lo.a.getY() - lo.getSlope() * lo.a.getX()
    	}
    	return intercept
    }
    
    //获取点A
    func (lo LinearObject) getA() Point {
    	return lo.a
    }
    
    //获取点B
    func (lo LinearObject) getB() Point {
    	return lo.b
    }
    
  3. LineSegmentObject 类型实现 LineSegment接口和 Oner 接口

    //是否在线段上
    func (lso LineSegmentObject) isOn(o Point) bool {
    	var isInSegment bool = false
    	//首先判断该点是否在LinearObject对象中两点构成的矩形中
    	minX := math.Min(lso.ls_lo.a.x,lso.ls_lo.b.x)
    	maxX := math.Max(lso.ls_lo.a.x,lso.ls_lo.b.x)
    	minY := math.Min(lso.ls_lo.a.y,lso.ls_lo.b.y)
    	maxY := math.Max(lso.ls_lo.a.y,lso.ls_lo.b.y)
    	//该点在两点构成的矩形中
    	if (o.x >= minX && o.x <= maxX) && (o.y >= minY && o.y <= maxY) {
    		//判断斜率是否相等
    		if (o.getY() - lso.ls_lo.getA().getY()) /
    			(o.getX() - lso.ls_lo.getA().getX()) == lso.ls_lo.getSlope() {
    			isInSegment = true
    		}
    	}
    	return isInSegment
    }
    
    //获取线段长度
    func (lso LineSegmentObject) getLength() float64 {
    	var sum float64 = 0.0
    	sum = sum + math.Pow((lso.ls_lo.getA().getX() - lso.ls_lo.getB().getX()),2)
    	sum = sum + math.Pow((lso.ls_lo.getA().getY() - lso.ls_lo.getB().getY()),2)
    	sum = math.Sqrt(sum)
    	return sum
    }
    
  4. Ray 类型实现 Oner 接口

    //判断点是否在射线上
    func (r Ray) isOn(o Point) bool {
    	//由于不清楚射线的方向,暂时将x较小的点作为端点
    	//斜率不小于0
    	if r.r_lo.getSlope() >= 0 {
    		//排除非法区间
    		if o.getX() < r.r_lo.a.getX() ||
    			o.getY() < r.r_lo.a.getY() {
    			return false
    		}
    	} else {
    		//排除非法区间
    		if o.getX() < r.r_lo.a.getX() ||
    			o.getY() > r.r_lo.a.getY() {
    			return false
    		}
    	}
    	//区间合法,判断斜率是否相等
    	if (o.getY() - r.r_lo.getA().getY()) /
    		(o.getX() - r.r_lo.getA().getX()) == r.r_lo.getSlope() {
    		return true
    	} else {
    		return false
    	}
    }
    
  5. Line 类型实现Oner接口

    //判断点是否在直线上
    func (l Line) isOn(o Point) bool {
    	if (o.getY() - l.l_lo.getA().getY()) /
    		(o.getX() - l.l_lo.getA().getX()) == l.l_lo.getSlope() {
    		return true
    	} else {
    		return false
    	}
    }
    

四. 测试部分

测试以直线 y = 3 * x + 1 作为参考,其中 x 取值采用随机函数生成 [0,500) 之间的整数并转换为 float64 类型。y 的取值包括随机产生值 y1 和上面直线的计算值 y2 两种方式,最后仅有一个 y 值,在 y1 和 y2 中随机挑选。在判断点是否在射线上时,有如下约定:取 x 较小值的点作为端点。测试样例一共 100 个。

  • 定义数组存放测试点,随机产生测试点
    	//定义数组,大小100,存放随机数,用于测试
    	var pointArr [100] Point
    	//产生随机数,设置种子(当前系统时间)
    	rand.Seed(time.Now().UnixNano())
    	for i := 0; i < 100 ; i++ {
    		//范围在0到500
    		x1 := float64(rand.Intn(500))
    		y1 := 3 * x1 + 1
    		y2 := float64(rand.Intn(500))
    		//在y1和y2中随机选取一个(y1在直线上,y2不一定)
    		s := rand.Intn(2)
    		var p Point
    		if s == 0 {
    			p = Point{x:x1,y:y1}
    		} else {
    			p = Point{x:x1,y:y2}
    		}
    		pointArr [i] = p
    	}
    
  • 定义点 A 和 点 B,确定直线
    	//定义两点
    	pointA := Point{x:200.0,y:601.0}
    	pointB := Point{x:300.0,y:901.0}
    
  • 定义 LinearObject,线段对象,射线对象,直线对象
    	//定义LinearObject,由两点组成
    	linearObject := LinearObject{a:pointA,b:pointB}
    	//定义线段对象
    	linearSegmentObject := LineSegmentObject{ls_lo:linearObject}
    	//定义射线对象
    	ray := Ray{r_lo:linearObject}
    	//定义直线对象
    	line := Line{l_lo:linearObject}
    
  • 测试代码
    	//测试所有点,输出测试结果
    	for i, p := range pointArr {
    		var isOnLine Oner
    		isOnLine = line
    		fmt.Print("点C(",pointArr[i].x)
    		fmt.Print(",",pointArr[i].y)
    		fmt.Println(")是否在点A和点B构成的直线上:",isOnLine.isOn(p))
    
    		//射线和直线接口对象
    		var isOnRay Oner
    		isOnRay = ray
    		fmt.Print("点C(",pointArr[i].x)
    		fmt.Print(",",pointArr[i].y)
    		fmt.Println(")是否在点A和点B构成的射线上:",isOnRay.isOn(p))
    
    		//线段接口对象
    		var lineSegment LineSegment
    		lineSegment = linearSegmentObject
    		fmt.Print("点C(",pointArr[i].x)
    		fmt.Print(",",pointArr[i].y)
    		fmt.Println(")是否在点A和点B构成的线段上:",lineSegment.isOn(p))
    
    		fmt.Println()
    	}
    

五. 部分测试结果截图
用 Go 语言实现直线,射线,线段的实例程序,并满足 SRP,OCP 设计原则。_第1张图片用 Go 语言实现直线,射线,线段的实例程序,并满足 SRP,OCP 设计原则。_第2张图片

六. 总结

说说对 Go 语言使用的体会,花了一个下午的时间学习了一下 Go 语言,上手还是很轻松的,和 C 语言很相似,因为没有类这个概念,一度让我觉得他是一门面向过程的语言,直到我看到了接口这部分内容,才确定 Go 语言是一门面向对象的语言,但作为面向对象语言他却没有继承这种概念,在 Java,Dart 等语言中,如果你想实现某个接口会用到 implements 关键字,而这在 Go 中是不存在的,Go 选择了隐式的方式实现接口,即当你把一个接口中的所有方法都实了,你就已经实现了该接口。因为没有类,所以应该也不能有对象,取而代之的是 struct,这是一种类型。在 Java 中,一个类中有属性和方法,而在 Go 中将属性和方法分离,属性放在 struct 中,方法放在接口中,并且一个类型可以实现多个接口,这是一种组合,组合比继承更灵活;同时多个类型可以实现同一个接口,实现了多态。能做到多态,就进一步确定是面向对象的语言。

要学习的东西还很多,慢慢来,比较快。

你可能感兴趣的:(Go,go,SRP,OCP)