• Scala实验任务二


    任务要求:

    对于一个图形绘制程序,用下面的层次对各种实体进行抽象。定义一个 Drawable 的特 质,其包括一个 draw 方法,默认实现为输出对象的字符串表示。定义一个 Point 类表示点, 其混入了 Drawable 特质,并包含一个 shift 方法,用于移动点。所有图形实体的抽象类为Shape,其构造函数包括一个 Point 类型,表示图形的具体位置(具体意义对不同的具体图 形不一样)。Shape 类有一个具体方法 moveTo 和一个抽象方法 zoom,其中 moveTo 将图形从 当前位置移动到新的位置, 各种具体图形的 moveTo 可能会有不一样的地方。zoom 方法实 现对图形的放缩,接受一个浮点型的放缩倍数参数,不同具体图形放缩实现不一样。继承 Shape 类的具体图形类型包括直线类 Line 和圆类 Circle。Line 类的第一个参数表示其位置, 第二个参数表示另一个端点,Line 放缩的时候,其中点位置不变,长度按倍数放缩(注意, 缩放时,其两个端点信息也改变了),另外,Line 的 move 行为影响了另一个端点,需要对 move 方法进行重载。Circle 类第一个参数表示其圆心,也是其位置,另一个参数表示其半 径,Circle 缩放的时候,位置参数不变,半径按倍数缩放。另外直线类 Line 和圆类 Circle 都混入了 Drawable 特质,要求对 draw 进行重载实现,其中类 Line 的 draw 输出的信息样式 “Line:第一个端点的坐标--第二个端点的坐标)”,类 Circle 的 draw 输出的信息样式为 “Circle center:圆心坐标,R=半径”。如下的代码已经给出了 Drawable 和 Point 的定义, 同时也给出了程序入口 main 函数的实现,请完成 Shape 类、Line 类和 Circle 类的定义。

    case class Point(var x:Double,var y:Double) extends Drawable{ def shift(deltaX:Double,deltaY:Double){x+=deltaX;y+=deltaY}

    }

    trait Drawable{

    def draw(){println(this.toString)}

    }

    // 请完成 Shape 类、Line 类和 Circle 类的定义。

    object MyDraw{

    def main(args: Array[String]) { val p=new Point(10,30)

    p.draw;

    val line1 = new Line(Point(0,0),Point(20,20)) line1.draw

    line1.moveTo(Point(5,5)) //移动到一个新的点

    line1.draw line1.zoom(2) //放大两倍 line1.draw

    val cir= new Circle(Point(10,10),5) cir.draw

    cir.moveTo(Point(30,20)) cir.draw

    cir.zoom(0.5) cir.draw

    }

    Shape:

    因为shape中有抽象类所以需要引用abstract

    Line类:

     当一个类extends另外一个类的时候,override的规则基本如下:

    • 子类中的方法要覆盖父类中的方法,必须写override(参见foo)
    • 子类中的属性val要覆盖父类中的属性,必须写override(参见nameVal)
    • 父类中的变量不可以覆盖(参见nameVar)

    Scala中的override

    override是覆盖的意思,在很多语言中都有,在scala中,override是非常常见的,在类继承方面,它和java不一样,不是可写可不写的了,而是必须写的。如果不写而覆盖了对应的属性或者方法的话,编译器就会报错了。今天把scala中的override的各种地方都整理了一遍,以方便以后翻阅。

    基础用法

    /*
    基本的override特性
    */
    class A {
      val nameVal = "A"
      var nameVar = "A"
    
      def foo: String = {
        "A.foo"
      }
    }
    
    class B extends A {
      override val nameVal = "B"
      //override var nameVar = "B"  "variable nameVar cannot override a mutable variable"
      override def foo: String = {
        "B.foo"
      }
    }
    
    val b1 = new B
    b1.foo
    b1.nameVal
    b1.nameVar
    
    val b2 : A = new B
    b2.foo
    b2.nameVal
    b2.nameVar = "B"
    b2.nameVar
    
    
    输出:
    
    
    defined class A
    
    
    defined class B
    
    
    b1: B = B@9825fab
    res0: String = B.foo
    res1: String = B
    res2: String = A
    
    b2: A = B@c46c4a1
    res3: String = B.foo
    res4: String = B
    b2.nameVar: String = B
    res5: String = B

    当一个类extends另外一个类的时候,override的规则基本如下:

    • 子类中的方法要覆盖父类中的方法,必须写override(参见foo)
    • 子类中的属性val要覆盖父类中的属性,必须写override(参见nameVal)
    • 父类中的变量不可以覆盖(参见nameVar)

    在抽象类中可以不用写override

    /*
    trait的extent不需要override
    */
    trait T {
      def foo : String
      def bar : String
    }
    
    class TB extends T {
      def foo: String = {
        "TB.foo"
      }
    
      def bar: String = "TB.bar"
    }
    
    val tb = new TB
    tb.foo
    tb.bar
    
    
    trait TT  extends T {
      def bar :String = "TT.bar"
    }
    
    class TTB extends TT {
      def foo: String = "TTB.foo"
    }
    val ttb = new TTB
    ttb.foo
    ttb.bar
    
    输出:
    
    defined trait T
    
    
    defined class TB
    
    
    tb: TB = TB@2fb497ea
    res6: String = TB.foo
    res7: String = TB.bar
    
    
    defined trait TT
    
    
    
    defined class TTB
    
    
    
    ttb: TTB = TTB@346c06af
    res8: String = TTB.foo
    res9: String = TT.bar

    T是特性类,它定义了两个抽象方法,foo和bar。TB的类继承和实现了T特性类,这个时候,TB类中的foo和bar前面的override是可写可不写的。这里初步看下TB类中的foo和bar前面的override写和不写感觉都一样,但是一旦有钻石结构的类继承,这个override的作用就体现出来了。这个我们后续说。

    TT和TTB的例子也是说明了下trait继承trait是不需要使用override的。

    abstrct class 也不需要使用override

    /*
    abstrct class 不需要override
    */
    abstract class PA(name: String) {
      def hello: String
    }
    
    class PB(name: String) extends PA(name) {
      def hello : String = s"hello ${name}"
    }
    
    val pb = new PB("yejianfeng")
    pb.hello
    
    输出:
    
    defined class PA
    
    defined class PB
    
    pb: PB = PB@62840167
    res10: String = hello yejianfeng
    
    abstract class和trait的特性主要是在是否有构造参数,在override方面都是一样的。

    钻石结构

    所谓的钻石结构就是一个菱形的结构,一个基类,两个子类,最后一个类又继承这两个子类。那么如果这两个子类都包含一个基类的方法,那么最后的这个类也有这个方法,选择继承那个子类呢?

    /*
    钻石结构
    */
    trait Animal {
      def talk: String
    }
    
    trait Cat extends Animal {
      def talk: String = "I am Cat"
    }
    
    trait Monkey extends Animal {
      def talk: String = "I am monkey"
    }
    
    trait Dog extends Animal {
      override def talk: String = "I am Dog"
    }
    
    val kittyDog = new Cat with Dog
    kittyDog.talk
    
    class MonkeyCat extends Monkey with Cat {
      override def talk: String = "I am monkeyCat"
    }
    
    val monkeyCat = new MonkeyCat
    monkeyCat.talk
    
    
    输出:
    
    defined trait Animal
    
    
    
    defined trait Cat
    
    
    
    defined trait Monkey
    
    
    
    defined trait Dog
    
    
    
    kittyDog: Cat with Dog = $anon$1@5378ef6d
    res11: String = I am Dog
    
    defined class MonkeyCat
    
    
    
    monkeyCat: MonkeyCat = MonkeyCat@1e444ce6
    res12: String = I am monkeyCat
    

    在这个例子中,Animal是基类,Cat和Dog是子类,kittyDog是继承了Cat和Dog,那么kittyDog里面的talk使用的是Cat和Dog中有标示override的那个方法。这个时候override的作用就体现出来了。

    参数复写使用override

    我们可以直接在构造函数里面使用override重写父类中的一个属性。我理解这个更多是语法糖的一个功能。

    /*
    参数复写
    */
    class Person(val age : Int){
      val name = "no name"
    }
    
    class XiaoMing(age: Int, override val name: String) extends Person(age){
    
    }
    val xiaoming = new XiaoMing(12, "xiaoming")
    xiaoming.name
    
    
    输出:
    defined class Person
    
    
    
    defined class XiaoMing
    
    
    xiaoming: XiaoMing = XiaoMing@2eef0f3c
    res13: String = xiaoming


    转自:https://www.cnblogs.com/yjf512/p/8026611.html

     最终效果:

  • 相关阅读:
    如何选择Html.RenderPartial和Html.RenderAction
    [转]使用 HTML5 WebSocket 构建实时 Web 应用
    基于.NET平台常用的框架整理
    0303
    XMLHTTP
    0120如何合并两个使用 System.Xml 使用 Visual C#.NET 的 XML 文档中的数据
    后台动态创建datatable0115
    笔记1126ASP.NET面试题(转)
    笔记1015
    数组与ARRAYLIST的关系与区别(转)
  • 原文地址:https://www.cnblogs.com/muailiulan/p/12252695.html
Copyright © 2020-2023  润新知