精华内容
参与话题
问答
  • C#.NET_面向对象编程技术

    万人学习 2015-01-08 08:56:25
    通俗易懂的面向对象编程技术,详细讲解C#.NET编程原理,.NET框架,辅以编程实例,具体的项目案例。从基础知识到项目开发,由入门到精通。 以形象的描术,把生涩的技术生动形象化,易理解,易掌握。
  • 什么是面向对象编程面向对象编程语言? 面向对象编程的英文缩写是 OOP,全称是 Object Oriented Programming 面向对象编程语言的英文缩写是 OOPL,全称是 Object Oriented Programming Language 面向对象编程 面向...

    什么是面向对象编程和面向对象编程语言?

    面向对象编程的英文缩写是 OOP,全称是 Object Oriented Programming
    面向对象编程语言的英文缩写是 OOPL,全称是 Object Oriented Programming Language

    面向对象编程

    面向对象编程是一种编程范式或编程风格。它以类和对象最为组织代码的基本单元,并将封装、抽象、继承、多态四个特性作为代码设计和实现的基石。

    面向对象编程语言

    面向对象编程语言是支持类和对象的语法机制,并有现成的语法机制,能方便的实现面向对象编程四大特性的编程语言。

    发展历史

    面向对象编程的两个重要概念:类(class)和对象(Object)。这两个概念最早提出在1960年,首次被使用是在Simula编程语言中。而面向对象编程第一次被使用是在Smalltalk编程语言中。所以Smalltalk是第一个真正意义上的面向对象编程语言。

    1980 年左右,C++ 的出现,带动了面向对象编程的流行,也使得面向对象编程被越来越多的人认可。直到今天,如果不按照严格的定义来说,大部分编程语言都是面向对象编程语言,比如 Java、C++、Go、Python、C#、Ruby、JavaScript、Objective-C、Scala、PHP、Perl 等等。

    如何判定一个编程语言是否是面向对象编程语言?

    如果按照严格的的定义,需要有现成的语法支持类、对象、四大特性才能叫作面向对象编程语言。如果放宽要求的话,只要某种编程语言支持类、对象语法机制,那基本上就可以说这种编程语言是面向对象编程语言了,不一定非得要求具有所有的四大特性。

    什么是面向对象分析和面向对象设计?

    面向对象分析(OOA),全称是Object Oriented Analysis
    面向对象设计(OOD),全称是Object Oriented Design

    OOA、OOD、OOP三个连起来就是面向对象软件开发要经历的三个阶段:需求分析、系统设计、编程实现。通俗的讲:面向对象分析就是要搞清楚做什么,面向对象设计就是要搞清楚怎么做,面向对象编程就是将分析和设计的的结果翻译成代码的过程。

    展开全文
  • Scala面向对象编程

    万次阅读 2018-11-07 11:18:49
    Scala面向对象编程 Scala程序设计 第2版 - 原版.pdf 下载: https://download.csdn.net/download/u014646662/10805074 目录: 1 类与对象初步 2 引用与值类型 3 价值类 4 父类 5 Scala的构造器 6 类的字段 6.1...

    Scala面向对象编程

    Scala程序设计 第2版 - 原版.pdf 下载:

    https://download.csdn.net/download/u014646662/10805074

    目录:

    1 类与对象初步
    2 引用与值类型
    3 价值类
    4 父类
    5 Scala的构造器
    6 类的字段
        6.1 统一访问原则
        6.2 一元方法
    7 验证输入
    8 调用父类构造器与良好的面向对象设计
    9 嵌套类型

    对人工智能感兴趣的同学,可以点击以下链接:

    现在人工智能非常火爆,很多朋友都想学,但是一般的教程都是为博硕生准备的,太难看懂了。最近发现了一个非常适合小白入门的教程,不仅通俗易懂而且还很风趣幽默。所以忍不住分享一下给大家。点这里可以跳转到教程。

    https://www.cbedai.net/u014646662

    Scala 是一个函数式编程语言,也是一个面向对象的编程语言,与Java、Python、Ruby、Smalltalk 等其他语言一样。在此强调两点,首先,函数式编程已经成为解决现代编程问题的一项基本技能,这个技能对你而言可能是全新的。开始使用Scala 时,人们很容易把它作为一个“更好的Java”语言来使用,而忽略了它“函数式的一面”。其次,Scala 在架构层面上提倡的方法是:小处用函数式编程,大处用面向对象编程。用函数式实现算法、操作数据,以及规范地管理状态,是减少bug、压缩代码行数和降低项目延期风险的最好方法。另一方面,Scala 的OO 模型提供很多工具,可用来设计可组合、可复用的模块。这对于较大的应用程序是必不可少的。因此,Scala 将两者完美地结合在了一起。

    1 类与对象初步

    类用关键字class 声明,而单例对象用关键字object 声明;(单例模式和Java的实现方式不同)

    在类声明之前加上关键字final,可以避免从一个类中派生出其他类;

    abstract 关键字可以阻止类的实例化;

    一个实例可以使用this 关键字指代它本身。(。尽管在Java 代码中经常看到this 的这种用
    法,Scala 代码中却很少看到。原因之一是,Scala 中没有样板构造函数。)

    Java创建一个Person类:

    package cn.com.tengen.test;
    
    public class Person {
        private String name;
        private int age;
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        public void setName(String name) { this.name = name; }
        public String getName() { return this.name; }
        public void setAge(int age) { this.age = age; }
        public int getAge() { return this.age; }
    }

    但是如果用Scala实现就比较简单了

    package cn.com.tengen.test
    
    class Person(var name: String, var age: Int){
    
    }
    

    使用scala测试一下

    package cn.com.tengen.test.obj
    
    class Person(var name: String,var age: Int){
    
    }
    
    object Person extends App {
    
        val p = new Person("Lucky",18)
      p.age = 20
        println(p.name+"---"+p.age)
    
    }

    输出结果:

    Lucky---20

    在构造参数前加上var,使得该参数成为类的一个可变字段,这在其他的OO 语言中也称为实例变量或属性。

    在构造参数前加上val,使得该参数成为类的一个不可变字段,

    用case 关键字可以推断出val,同时自动增加一些方法,如下所示:

    package cn.com.tengen.test.obj
    
    case class ImmutablePerson(name: String, age: Int) {
    
    }
    
    object ImmutablePerson extends App{
      val p = new ImmutablePerson("Lucky",18)
      println(p.name+"---"+p.age)
    }

    case做了那些事:

    1.重写了toString
    2.默认实现了equals 和hashCode
    3.默认是可以序列化的,也就是实现了Serializable
    4.自动从scala.Product中继承一些函数
    5.case class构造函数的参数是public级别的,我们可以直接访问
    6.支持模式匹配
    7.实现了copy方法

    method(方法)指与实例绑定在一起的函数。换句话说,它的参数列表中有一个“隐含”的this 参数。方法用关键字def 定义。当其他函数或方法需要一个函数作为参数时,Scala 会自动将可用的方法“提升”为函数,作为前者的函数参数。

    如同大多数静态类型语言一样,Scala 允许方法重载。只要各方法的完整签名是唯一的,两个或更多方法就可以具有相同的名称。方法的签名包括返回类型,方法名称和参数类型的列表(参数的名称不重要)。因此,在JVM 中只凭不同的返回类型不足以区分不同的方法。

      def f1(s : String): Unit ={
        println(s)
      }
    
      def f1(s : String,i : Int): Unit ={
        println(s)
      }

    类型名称必须唯一。

    成员是类的字段、方法或类型的统称。与Java 不同,如果方法有参数列表,该方法可以与类的字段同名:

    2 引用与值类型

    Java 语法为JVM 实现数据的方式提供了模型。首先,它提供了一组原生类型:short、int、long、float、double、boolean、char、byte 和关键字void。它们被存储在堆栈中,或为了获得更好的性能,被存储于CPU 寄存器。

    Scala 固然必须符合JVM 的规则,但Scala 做了改进,使得原生类型和引用类型的区别更明显。

    所有引用类型都是AnyRef 的子类型。AnyRef 是Any 的子类型,而Any 是Scala 类型层次的根类型。所有值类型均为AnyVal 的子类型,AnyVal 也是Any 的子类型。Any 仅有这两个直接的子类型。需要注意,Java 的根类型Object(http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html)实际上更接近Scala 的AnyRef,而不是Any。
    引用类型仍用new 关键字来创建。类似其他不带参数的方法一样,如果构造器不带参数(在有的语言中称为“默认构造器”),我们在使用构造器时也可以去掉后面的括号。


    Scala 沿用了Java 中数字和字符串的字面量语法。例如: 在Scala 中,val name ="Programming Scala" 与val name = new String("Programming Scala") 等价。不过,Scala还为元组增加了字面量语法,(1,2,3) 就等价于new Tuple3(1,2,3)。我们已经接触过Scala的一些语言特性,可以实现编译器原本不支持的字面量写法,如:用1 :: 2 :: 3 :: Nil表示Map("one" ->, "two" -> 2)。
    用带apply 方法的对象创建引用类型的实例是很常见的做法,apply 方法起到工厂的作用(这种方法必须在内部调用new 或对应的字面量语法)。由于case 类会自动生成伴随对象及其apply 方法,因此case 类的实例通常就是用这种方法创建出来的。
    Short、Int、Long、Float、Double、Boolean、Char、Byte 和Unit 类型称为值类型,分别对应JVM 的原型short、int、long、float、double、boolean、char、byte 和void 关键字。在Scala 的对象模型中,所有的值类型均为AnyVal 的子类型,AnyVal 是Any 的两个子类型之一。
    值类型的“实例”不是在堆上创建的。相反,Scala 用JVM 原生类型来表示值类型,它们的值都存放在寄存器或栈上。值类型的“实例”总是用字面量来创建,如1,3.14,true。Unit 对应的字面量是(),不过我们很少显式地使用。
    事实上,值类型没有构造器,所以像val I = new Int(1) 这样的表达式将无法通过编译。

    3 价值类

    package cn.com.tengen.test.obj
    
    class Dollar(val value: Float) extends AnyVal {
      override def toString = "$%.2f".format(value)
    }
    object Dollar extends App{
      val hello = new Dollar(100)
      println(hello)
    }
    
    
    //输出结果:$100.00

    要成为一个有效的价值类,必须遵守以下的规则。

    (1) 价值类有且只有一个公开的val 参数(对于Scala 2.11,该参数也可以是不公开的)。
    (2) 参数的类型不能是价值类本身。
    (3) 价值类被参数化时,不能使用@specialized(http://www.scala-lang.org/api/current/scala/specialized.html)标记。
    (4) 价值类没有定义其他构造器。
    (5) 价值类只定义了一些方法,没有定义其他的val 和var 变量。
    (6) 然而,价值类不能重载equals 和hashCode 方法。
    (7) 价值类定义没有嵌套的特征、类或对象。
    (8) 价值类不能被继承。
    (9) 价值类只能继承自通用特征。
    (10) 价值类必须是对象可引用的一个顶级类型或对象的一个成员。

    通常,被包装的类型是AnyVal 的子类型之一,但并不是必须如此。如果换成引用类型,我们仍然可以受益于内存不在堆上分配的优势。例如,下例中,隐含了对电话号码字符串的包装:

    package cn.com.tengen.test.obj
    
    class USPhoneNumber(val s: String) extends AnyVal {
      override def toString = {
        val digs = digits(s)
        val areaCode = digs.substring(0,3)
        val exchange = digs.substring(3,6)
        val subnumber = digs.substring(6,10) // “客户编号”
        s"($areaCode) $exchange-$subnumber"
      }
      private def digits(str: String): String = str.replaceAll("""\D""", "")
    }
    
    object USPhoneNumber extends App{
      val number = new USPhoneNumber("987-654-3210")
      println(number)
    }
    
    //输出结果:(987) 654-3210
    

    一个通用特征具有以下特性:

    (1) 它可以从Any 派生(而不能从其他通用特征派生)。
    (2) 它只定义方法。
    (3) 它没有对自身做初始化。

    下面给出了一个改进版的USPhoneNumber,这里混用了两个通用特征:

    package cn.com.tengen.test.obj
    
    /**
      * Digitizer 是一个通用特征,定义了我们之前的digits 方法。
      */
    trait Digitizer extends Any {
      def digits(s: String): String = s.replaceAll("""\D""", "")
    }
    
    /**
      * Formatter 特征按我们想要的格式对电话号码进行格式化。
      */
    trait Formatter extends Any {
      def format(areaCode: String, exchange: String, subnumber: String): String =
        s"($areaCode) $exchange-$subnumber"
    }
    
    
    class USPhoneNumber(val s: String) extends AnyVal
      with Digitizer with Formatter {
      override def toString = {
        val digs = digits(s)
        val areaCode = digs.substring(0,3)
        val exchange = digs.substring(3,6)
        val subnumber = digs.substring(6,10)
        //调用Formatter.format。
        format(areaCode, exchange, subnumber)
      }
    }
    object USPhoneNumber extends App{
      val number = new USPhoneNumber("987-654-3210")
      println(number)
    }
    //输出结果:(987) 654-3210
    

    Formatter 实际上解决了一个设计上的问题。我们可能要给USPhoneNumber 指定另一个参数作为格式字符串,或需要一些机制去配置toString 的格式,因为流行的格式可能有很多。但是,我们只允许传递一个参数给USPhoneNumber。针对这种情况,我们可以在通用特征中去配置我们想要的格式!然而,由于JVM 的限制,通用特征有时会触发实例化(即实例的内存分配于堆中)。这里将需要实例化的情况总结如下。

    (1) 当价值类的实例被传递给函数作参数,而该函数预期参数为通用特征且需要被实例实现。不过,如果函数的预期参数是价值类本身,则不需要实例化。
    (2) 价值类的实例被赋值给数组。
    (3) 价值类的类型被用作类型参数。

    4 父类

    子类是从父类或基类中派生的派生类,是大部分面向对象语言的核心特征。这种机制用来重用、封装和实现多态行为(具体行为取决于实例在类型层次结构中的实际类型)。像Java 一样,Scala 只支持单一继承,而不是多重继承。子类(或派生类)可以有且只有一个父类(即基类)。唯一的例外是,Scala 的类型结构中的根类Any 没有父类。

    实例:

    abstract class BulkReader {
      type In
      val source: In
      def read: String // Read source and return a String
    }
    class StringBulkReader(val source: String) extends BulkReader {
      type In = String
      def read: String = source
    }
    class FileBulkReader(val source: java.io.File) extends BulkReader {
      type In = java.io.File
      def read: String = {...}
    }

    如在Java 中一样,关键字extend 表示后面是父类,因此本例中的父类为BulkReader。
    在Scala 中,当类继承trait 时,也用extend 表示(甚至当该类用with 关键字混入了其他trait时也是如此)。
    此外,当trait 是其他trait 或类的子trait 时,也用extend。是的,trait 可以继承类。
    如果我们不指定父类,默认父类为AnyRef。
     

    5 Scala的构造器

    Scala 将主构造器与零个或多个辅助构造器区分开,辅助构造器也被称为次级构造器。在Scala 中,主构造器是整个类体。构造器所需的所有参数都被罗列在类名称后面。

    package cn.com.tengen.test.obj
    
    case class Address(street: String, city: String, state: String, zip: String) {
      def this(zip: String) = this("[unknown]", Address.zipToCity(zip), Address.zipToState(zip), zip)
    }
    object Address {
      def zipToCity(zip: String) = "Anytown"
      def zipToState(zip: String) = "CA"
    }
    case class Person(name: String, age: Option[Int], address: Option[Address]) {
      def this(name: String) = this(name, None, None)
      def this(name: String, age: Int) = this(name, Some(age), None)
      def this(name: String, age: Int, address: Address) = this(name, Some(age), Some(address))
      def this(name: String, address: Address) = this(name, None, Some(address))
    }
    

    构造器调用

    object Main extends App{
      var address = new Address("Lucky");
      var p = Person("lucky",Some(20),Some(address));
      println(p.name+"---"+p.age.get+"---"+p.address.get)
    }

    在我们的实现中,用户使用 new 来创建实例,使用主构造器创建实例时new可以省略

    6 类的字段

    如果在主构造函数参数的前面加上val 或var 关键字,该参数就成为实例的一个字段。对于case 类,val 是默认的。这样可以大大减少冗余的代码。是Scala 会自动做Java 代码中明显做的事情。类会创建一个私有的字段,并生产对应的getter 和setter 访问方法。

    class Name (var value: String)

    改代码等价于

    class Name(s: String){
      private var _value: String = s //不可见的字段,在本例中声明为可变变量。
      def value: String = _value //getter,即读方法。
      def value_= (newValue: String): Unit = _value = newValue //setter,即写方法。
    }

    注意value_= 这个方法名的一般规范。当编译器看到这样的一个方法名时,它会允许客户端代码去掉下划线_,转而使用中缀表达式,这就好像我们是在设置对象的一个裸字段一样:

    object Main extends App{
      val name = new Name("Lucky")
      println(name.value)
      name.value_=("Helen")
      println(name.value)
      name.value="Jon"
      println(name.value)
      name.value=("Lucy")
      println(name.value)
    }
    
    运行结果:
    Lucky
    Helen
    Jon
    Lucy

    6.1 统一访问原则

    Scala 没有遵循JavaBeans 的约定规范,没有把value 字段的读方法和写方法分别命名为getValue 和setValue,但是Scala 遵循统一访问的原则。正如我们在Name 这个例子中看到的,客户端似乎可以不经过方法就对“裸”字段值进行读和写的操作,但实际上它们调用了方法。

    请注意,用户的“体验”是一致的。用户代码不了解实现,这使我们可以在需要的时候,自由地将直接操作裸字段改为通过访问方法来操作。例如:我们要在写操作中添加某些验证工作,或者为了提高效率,在读取某个结果时采用惰性求值。这些情况下,我们可以通过访问方法来操作裸字段。相反地,我们也可以用公开可见性的字段代替访问方法,以消除该方法调用的开销(尽管JVM 可能会消除这种开销)。因此,统一访问原则的重要益处在于,它能最大程度地减少客户端代码对类的内部实现所必须了解的知识。尽管重新编译仍然是必需的,我们可以改变具体实现,而不必强制客户端代码跟着做出改变。

    Scala 实现统一访问原则的同时,没有牺牲访问控制功能,并且满足了在简单的读写基础上增加其他逻辑的需求。

    6.2 一元方法

    package cn.com.tengen.test.obj
    
    case class Complex(real: Double, imag: Double) {
      //方法名为unary_X,这里X 就是我们想要使用的操作符。在本例中,X 就是-。注意-和: 之间的空格,空格在这里是必须的,它可以告诉编译器方法名以- 而不是: 结尾!为了比较,我们也实现了常见的减号操作符。
      def unary_- : Complex = Complex(-real, imag)
      def -(other: Complex) = Complex(real - other.real, imag - other.imag)
    }
    
    object Main extends App{
      val c1 = Complex(88.8, 88.8)
      val c2 = -c1
      val c3 = c1.unary_-
      val c4 = c1 - Complex(22.2, 22.2)
      println(c1)
      println(c2)
      println(c3)
      println(c4)
    }
    
    输出结果:
    Complex(88.8,88.8)
    Complex(-88.8,88.8)
    Complex(-88.8,88.8)
    Complex(66.6,66.6)
    

    方法名为unary_X,这里X 就是我们想要使用的操作符。在本例中,X 就是-。

    注意-和: 之间的空格,空格在这里是必须的,它可以告诉编译器方法名以- 而不是: 结尾!

    我们一旦定义了一元操作符,就可以将操作符放在实例之前,就像我们在定义c2 时所做的那样。也可以像定义c3 时那样,将一元操作符当做其他方法一般进行调用。

    7 验证输入

    保证创建实例参数处于有效的状态,示例如下:

    package cn.com.tengen.test.obj
    
    case class ZipCode(zip: Int, extension: Option[Int] = None) {
      // 使用require 方法验证输入。
      require(valid(zip, extension),  s"Invalid Zip+4 specified: $toString")
      protected def valid(z: Int, e: Option[Int]): Boolean = {
        if (0 < z && z <= 99999) e match {
          case None => validUSPS(z, 0)
          case Some(e) => 0 < e && e <= 9999 && validUSPS(z, e)
        }
        else false
      }
    
      /**
        * 真正的方法实现应该查询USPS 认可的数据库来验证邮政编码是否确实存在。
        */
      protected def validUSPS(i: Int, e: Int): Boolean = true
    
      /**
        * 覆写toString 方法,返回符合人们预期的邮政编码格式,对结尾可能的四位数字进行覆写toString 方法,
        * @return 返回符合人们预期的邮政编码格式,对结尾可能的四位数字进行
        */
      override def toString =  if (extension != None) s"$zip-${extension.get}" else zip.toString
    }
    object ZipCode {
      def apply (zip: Int, extension: Int): ZipCode =
        new ZipCode(zip, Some(extension))
    
      def main(args: Array[String]): Unit = {
        var z1 = ZipCode(12345)
        println(z1) //12345
        var z2 = ZipCode(12345, Some(6789))
        println(z2) //12345-6789
        var z3 = ZipCode(123456)
        println(z3) //异常 java.lang.IllegalArgumentException: requirement failed: Invalid Zip+4 specified: 123456
      }
    }
    

    定义ZipCode 这种领域专用的类的充分理由是:这种类可以在构造时对值的有效性做一次 检验,然后类ZipCode 的使用者就不再需要再次检验了。

    虽然我们在构造器的背景下讨论输入的验证,但实际上我们也可以在任何方法中调用这些断言方法。然而,价值类的类体是一个例外,它不能使用断言验证,否则就需要调用分配堆。不过,由于ZipCode 带有两个构造器参数,它无论如何不会是价值类。

    8 调用父类构造器与良好的面向对象设计

    派生类的主构造器必须调用父类的构造器,可以是父类的主构造器或次级构造器。

    package cn.com.tengen.test.obj
    
    case class Address(street: String, city: String, state: String, zip: String) {
      def this(zip: String) = this("[unknown]", Address.zipToCity(zip), Address.zipToState(zip), zip)
    }
    
    object Address {
      def zipToCity(zip: String) = "Jiaxing"
      def zipToState(zip: String) = "CA"
    }
    
    case class Person( name: String, age: Option[Int] = None, address: Option[Address] = None)
    
    class Employee( name: String, age: Option[Int] = None,  address: Option[Address] = None, val title: String = "[unknown]",  val manager: Option[Employee] = None) 
      extends Person(name, age, address) {
      override def toString = s"Employee($name, $age, $address, $title, $manager)"
    }
    
    object Employee extends App {
      val a1 = new Address("1 Scala Lane", "Anytown", "CA", "98765")
      val a2 = new Address("98765")
      val ceo1 = new Employee("Joe CEO", title = "CEO")
      println(ceo1) //Employee(Joe CEO, None, None, CEO, None)
      val ceo2 = new Employee("Buck Trends1");
      println(ceo2) //Employee(Buck Trends1, None, None, [unknown], None)
    }

    在Java 中,我们会定义构造方法,并用super 调用父类的初始化逻辑。而Scala 中,我们用ChildClass(…) extends ParentClass(…) 的语法隐式地调用父类的构造器。

    当使用继承时,建议遵循以下规则。

    (1) 一个抽象的基类或trait,只被下一层的具体的类继承,包括case 类。
    (2) 具体类的子类永远不会再次被继承,除了两种情况:
    	a. 类中混入了定义于trait中的其他行为。理想情况下, 这些行为应该是正交的, 即不重叠的。
    	b. 只用于支持自动化单元测试的类。
    (3) 当使用子类继承似乎是正确的做法时,考虑将行为分离到trait 中,然后在类里混入这些trait。
    (4) 切勿将逻辑状态跨越父类和子类。

    换一种实现方式:

    Employee 不再是Person 的一个子类,但它是PersonState 的一个子类,因为它混入了该trait。

    package cn.com.tengen.test.obj
    
    case class Address(street: String, city: String, state: String, zip: String)
    
    object Address {
      def apply(zip: String) = new Address("[unknown]", Address.zipToCity(zip), Address.zipToState(zip), zip)
      def zipToCity(zip: String) = "Anytown"
      def zipToState(zip: String) = "CA"
    }
    
    trait PersonState {
      val name: String
      val age: Option[Int]
      val address: Option[Address]
    }
    
    case class Person(name: String,age: Option[Int] = None,address: Option[Address] = None)
      extends PersonState
    
    trait EmployeeState {
      val title: String
      val manager: Option[Employee]
    }
    case class Employee(name: String,age: Option[Int] = None, address: Option[Address] = None, title: String = "[unknown]", manager: Option[Employee] = None)
      extends PersonState with EmployeeState
    
    object Person extends App{
      val ceoAddress = Address("1 Scala Lane", "Anytown", "CA", "98765")
      println(ceoAddress)
      val buckAddress = Address("98765")
      println(buckAddress)
      val ceo = Employee( name = "Joe CEO", title = "CEO", age = Some(50), address = Some(ceoAddress), manager = None)
      println(ceo)
      val ceoSpouse = Person("Jane Smith", address = Some(ceoAddress))
      println(ceoSpouse)
      val buck = Employee(  name = "Buck Trends", title = "Zombie Dev", age = Some(20), address = Some(buckAddress), manager = Some(ceo))
      println(buck)
      val buckSpouse = Person("Ann Collins", address = Some(buckAddress))
      println(buckSpouse)
    }
    
    
    输出结果:
    Address(1 Scala Lane,Anytown,CA,98765)
    Address([unknown],Anytown,CA,98765)
    Employee(Joe CEO,Some(50),Some(Address(1 Scala Lane,Anytown,CA,98765)),CEO,None)
    Person(Jane Smith,None,Some(Address(1 Scala Lane,Anytown,CA,98765)))
    Employee(Buck Trends,Some(20),Some(Address([unknown],Anytown,CA,98765)),Zombie Dev,Some(Employee(Joe CEO,Some(50),Some(Address(1 Scala Lane,Anytown,CA,98765)),CEO,None)))
    Person(Ann Collins,None,Some(Address([unknown],Anytown,CA,98765)))
    

    9 嵌套类型

    Scala 允许我们嵌套类型的成名和定义。例如:在对象中定义类型转义的异常和其他有用的类型,就是很常见的做法。以下是一个数据库层可能的骨架结构:

    package cn.com.tengen.test.obj
    
    object Database {
      case class ResultSet(/*...*/)
      case class Connection(/*...*/)
      case class DatabaseException(message: String, cause: Throwable) extends RuntimeException(message, cause)
    
      /**
        * 使用sealed 的继承结构表示状态;所有允许的值都在这里定义。当实例实际上不携带状态信息时,使用case 对象。这些对象表现得像“标志位”,用来表示状态。
        */
      sealed trait Status
      case object Disconnected extends Status
      case class Connected(connection: Connection) extends Status
      case class QuerySucceeded(results: ResultSet) extends Status
      case class QueryFailed(e: DatabaseException) extends Status
    }
    class Database {
      import Database._
    
      /**
        * ??? 是定义在Predef 中的真实方法。它会抛出一个异常,用来表示某一方法尚未实现的情况。该方法是最近才引入Scala 库的。
        */
      def connect(server: String): Status = ???
      def disconnect(): Status = ???
      def query(/*...*/): Status = ???
    }

    当case 类没有用任何字段表示状态信息时,考虑使用case 对象。

    当方法还正处在开发阶段时,??? 方法作为占位符十分有用。因为这样可以使代码通过编译。问题是你没法调用那个方法!

    为case 对象生成的hashCode 方法仅仅将对象的名称做了散列。

     def main(args: Array[String]): Unit = {
        println(Disconnected.hashCode())
        println("Disconnected".hashCode())
      }
    
    输出结果:
    -1217068453
    -1217068453

     

    展开全文
  • 面向对象编程

    2007-10-15 14:33:00
    一:什么是面向对象编程? 面向对象(Object-Oriented)述语源于挪威的Kristen Nygaard在开发Simula-67程序语言时使用了对象(Object)概念。面向对象编程是以对象为基础,在对象之间传递消息来解决问题(actor ...

    一:什么是面向对象编程?
       面向对象(Object-Oriented)述语源于挪威的Kristen Nygaard在开发Simula-67程序语言时使用了对象(Object)概念。面向对象编程是以对象为基础,在对象之间传递消息来解决问题(actor theory)的编程方法。
    二:为什么要使用面向对象编程?
       1.相比过程化编程,使用面向对象编程方法写出来的程序更具有重用性和扩展性,而且可以大大提高开发效率。比如一个公司可以建立自己的程序框架(Application Framework)和函数库,然后可以在多个项目中使用。
       2.面向对象编程方法的思维模式与人们的思维模式相同,所以更容易分析、表现和解决现实世界中的具体问题。
       3.可以使用与面向对象相关的工具,比如建模工具(Rational Rose)、开发工具(Visual Studio.NETJ Builder)、形象管理工具(Rational Clear Case)
       4.面向对象编程方法的特性更适合多人合作开发(Team Development)。黑匣子(Black Box-是面向对象编程重要特性之一。你可以使用UML建模,然后按类或组件为一个单位交给程序员。因为这些任务单位(类或组件)之间依赖性很小,所以程序员写代码时不用考虑其他问题。
       5.面向对象编程方法更适合目前流行的开发工具和技术。目前流行的开发工具和技术都是以面向对象编程方法为基础的,所以你不知道面向对象编程,学习和应用它们就比较困难了。
    三:面向对象编程方法的特性
       1.面向对象编程方法是以对象为基础,所实现的功能是由对象之间传递消息来完成的。
       2.所有对象都有自己的内存空间,而且可以包含其他对象。
       3.所有对象是类的实例(Instance
         类是相同对象的集合(Set Of Objects
         类定义对象的属性和方法(Method
     

        1>对象(Object
          定义: An object is a software bundle of variables and related methods.
          现实世界中每个物体都有自己的变量和行为,比如说手机,型号,价格等就是手机的变量,手机可以发送短消息,下载铃声等就是手机的行为。面向对象编程当中的对象是从现实世界中的物体中抽象出来的。在面向对象编程中,变量叫作属性(Property),行为叫作方法(Method)。对象所知道的(Knows)和所能做的(Can do)都是由其属性和方法来决定的。
        2>消息(Message
          对象之间的交互是利用消息来完成的,每个对象收到消息之后,就执行相应的操作,然后返还结果。有时候对象需要附加的信息,来执行操作。比如你的手机对象要发送短消息,就必须知道要发给谁。这些附加信息是通过消息按参数的方式传递给对象的。需要注意的是,虽然是相同的消息,但对于不同的对象,执行后的结果是不一样的。对于教授来说work可能是给学生上课,而对于鲜花店的店员来说是卖鲜花。
        3>类(Class
          定义:A class is a blueprint, or prototype, that defines the variables and the methods common to all objects of a certain kind.
          类是相同对象的集合(Set Of Objects)。类定义相同对象的属性和方法。
        4>封装(Encapsulation
          封装就是上面所说的黑匣子(Black Box)特性。封装特性提供外界与对象交互的控制机制,我们可以把外界所需要的服务公开,而把其他服务隐藏在对象内部。这样可以让程序简单化,而且可以避免调用不必要的服务所带来的错误。
        5>抽象化(Abstraction
          抽象化是分析、过滤现实世界中的事物,导出对象的过程。抽象化是解决复杂问题的基本方法。程序员出身的分析员在做分析时常犯的错误是把具体实现考虑进来。其实分析阶段不用考虑某个功能应该怎样写成代码,只要把业务流程分析,然后导出必要的对象就可以了。
        6>继承与类型的兼容性(Inheritance
         使用面向对象编程方法的最大好处之一最是可以很容易地扩展原由的程序代码。这个特性就是继承。我们可以继承一个类生成新的类,原有类叫作父类(Parent Class)新类叫作子类(Child Class)。子类不仅拥有父类的所有属性和方法(不用写额外的代码),而且可以添加别的属性和方法。大多数编程语言对数据类型的定义是严格的,就是说,你不能在两个不同类型的数据之间进行赋值。但有些例外,我们可以把子类的对象赋值给父类对象。
       7>滞后联编与多态(Dynamic Binding & Ploymophism
         滞后联编是与静态联编(Static Binding)相反的一种联编方式。静态联编指的是由编译器或连接器来分析对象的方法调用,它们是通过调用函数或过程所占有的特殊内存地址(函数地址)来代替直接调用。而滞后联编是在程序运行时才确定所调用对象方法的实际地址。这种技术的优点被称作多态。如果运用好多态特性(结合继承特性),我们可以编写高重用性、高扩展性的程序。
        8>Overriding & Overloading
          Overriding指的是可以覆盖或重定义父类的动态方法(在子类中),Overloading 指的是在一个类或其子类中可以使用相同名称的方法,但参数必须要不同。

    结:
        1.使用面向对象编程方法我们可以写出具有高重用性和扩张性的程序,而且可以大大提高开发效率。
        2.面向对象编程是以对象为基础,在对象之间传递消息来解决问题(actor theory)的编程方法(All is object)。
        3.在项目初期没有很好的分析和设计,就不能写出具有重用性和扩展性的程序,而且会降低开发效率,所以在实际的项目中运用面向对象编程方法,需要慎重考虑。

    展开全文
  • 现在网络上还经常讨论函数式编程和面向对象编程。很多人认为,C语言编程,就是函数式编程,C++, JAVA等高级语言,才是面向对象编程。 其实,这是错误的认识!面向对象编程是一种思想,是一种编程思路,实现这种...

           结构体是一个非常重要的知识点,必须掌握和深入理解使用。现在网络上还经常讨论函数式编程和面向对象编程。很多人认为,C语言编程,就是函数式编程,C++, JAVA等高级语言,才是面向对象编程。

           其实,这是错误的认识!面向对象编程是一种思想,是一种编程思路,实现这种编程思路,不局限于是使用C语言还是使用C++语言。

           使用C语言也可以实现面向对象编程。例如linux的内核,这么复杂的一个操作系统,是使用C语言来设计完成,很多地方是使用了面向对象的编程思想。

           那么,使用C语言来实现“面向对象编程”思路,就是使用结构体来完成。C++中使用类来定义成员变量和方法,相应的,C语言也可以使用结构体来完成这项操作。C语言的结构体可以定义成员变量,同时,可以定义函数指针,实现C++类的方法。

           下面我通过程序测试例子来讲解“使用结构体实现面向对象编程”的知识。首先,给出程序测试例子代码:

           程序运行结果如下:

           在这个例子中,讲解一个图书管理系统中的借书和还书功能。对于读者来说,有普通读者和VIP读者。读者有借书和还书的操作。

           此时,我们使用面向对象编程的思想来设计程序。首先,分析设计程序要实现什么功能,它有什么对象进行活动,对象之间是什么关系,对象有什么操作。那么,我们可以归纳如下:

    (1) 程序是一个图书馆的借书和还书功能模块;

    (2) 程序是涉及到的活动对象是读者和图书;

    (3) 对象之间的活动关系是:读者结束、读者还书;

    (4) 读者有普通用户和VIP用户类型的区别;

    (5) 普通用户和VIP用户的借书和还书有普通的操作;

           所以,归纳出了这些问题,我们就可以有如下是设计思路:

    (1) 需要定义读者和图书这样的两个结构体类型;所以,我们定义了struct reader, struct book这样的结构体类型;

    (2) 读者结构体类型中,需要定义普通用户和VIP用户的区分属性;所以,在struct reader结构体类型中,定义了 is_vip属性,用于定义当前读者的身份类型;

    (3) 普通读者和VIP读者的借书和还书操作不一样,所以,定义普通读者操作是:

    void my_borrow_book(struct reader* preader, struct book* pbook)

    void my_payback_book(struct reader* preader, struct book* pbook)

    VIP读者的操作是:

    void my_vip_borrow_book(struct reader* preader, struct book* pbook)

    void my_vip_payback_book(struct reader* preader, struct book* pbook)

           这些函数操作是读者的一个属性,所以,需要给读者定义函数指针成员,指向具体的操作函数。如下:

    //定义函数指针, pfunc_borrow_book 类型的函数;

    pfunc_borrow_book borrow_book;

    //定义函数指针, pfunc_payback_book 类型的函数;

    pfunc_payback_book payback_book;

           最终,在init_reader_function()函数中,根据读者是否为VIP类型,给对象的函数指针成员指向不同的函数。如下:

        if(preader->is_vip)

        {

           //给函数指针赋值, 让它指向具体的函数;

           preader->borrow_book = my_vip_borrow_book;

           preader->payback_book = my_vip_payback_book;

        }

        else

        {

           preader->borrow_book = my_borrow_book;

           preader->payback_book = my_payback_book;

        }

           那么,不同的读者类型,调用相同的函数指针,就调用指向不同的函数。例如:

    r1.borrow_book(&r1, &b1);   //读者 r1 借书

    r2.borrow_book(&r2, &b2);   //读者 r2 借书

           此时,读者都是调用borrow_book函数指针指向的函数,那么,由于r1是普通用户,它的函数指针指向my_borrow_book()函数,所以,r1.borrow_book()调用的就是my_borrow_book()函数。

           同理,r2是VIP用户,它的borrow_book函数指针指向my_vip_borrow_book ()函数,所以,r2.borrow_book()调用的就是my_vip_borrow_book ()函数。

           通过这个例子,我们更深入地学习了结构体的应用,并提出了面向对象的编程思想。使用C语言的结构体知识可以实现面向对象编程。

    更多的交流可以访问:www.mylinux.vip   加QQ:1523520001,微信:13926572996,备注:linux编程;
    学习、分享更多的linux C/C++ 编程知识。
     

     

    展开全文
  • Java 面向对象编程.pdf

    千次下载 热门讨论 2012-12-24 17:41:29
    《Java 面向对象编程》内容由浅入深,紧密结合实际,利用大量典型实例,详细讲解Java面向对象的编程思想、编程语法和设计模式,介绍常见Java类库的用法,总结优化Java编程的各种宝贵经验,深入阐述Java虚拟机执行...
  • JavaScript ES6面向对象编程

    千人学习 2018-05-11 17:38:33
    JavaScript中的面向对象编程是个难点。那这个课程会非常详细去介绍面向对象,其中晦涩的概念都会用非常通俗的语言去阐述!课程里面还包括ES6的面向对象,通过这套课程会让你彻底弄明白面向对象!
  • Go:面向对象编程

    万次阅读 2020-06-01 09:49:21
    Go语言面向对象编程
  • 面向接口编程和面向对象编程的区别

    万次阅读 多人点赞 2017-11-02 11:21:40
    我想,对于各位使用面向对象编程语言的程序员来说,“接口”这个名词一定不陌生,但是不知各位有没有这样的疑惑:接口有什么用途?它和抽象类有什么区别?能不能用抽象类代替接口呢?而且,作为程序员,一定经常听到...
  • 面向过程编程,面向对象编程和面向切面编程理解

    千次阅读 多人点赞 2017-03-17 19:28:55
    面向过程(Procedure ...面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。OOP 达到
  • 什么是面向对象编程

    千次阅读 多人点赞 2020-01-12 18:57:20
    本文关键字:面向对象、面向过程、面向过程编程语言、面向对象编程语言。说到编程,对于初学者来讲,可能第一想到的就是敲键盘,写代码,做游戏,甚至于会联想到软件破解、网络攻防。另一方面,在学了一些编程的相关...
  • js面向对象编程

    千次阅读 多人点赞 2020-02-23 22:07:02
    面向对象编程其实是一种思想(面向过程,面向对象) 面向过程: 比如说你现在肚子饿了,想要去吃面条,那么在做面条的过程中用多少面粉,用多少水,怎么和面和切面条 ...
  • 面向对象编程转为面向接口编程

    千次阅读 2018-08-19 01:48:07
    但是,如果只是停留在面向对象编程,而不是继续向前看。那么,无疑是一种固步自封的陷阱。 更加先进的编程思想是什么呢? 就是面向接口编程。   这里,涉及到一个哲学问题。到底是以类型封装特征,还是以特征...
  • JS深度揭秘第五章-面向对象编程

    千人学习 2018-11-14 17:59:40
    此章节会详细介绍对象的概念,包含javascript的内置对象、ES6增加的内置对象等。会着重的讲解面向对象编程,通俗的解释...用独特的方式去讲解面向对象编程的方式以及ES6的面向对象编程,可以很轻松的理解面向对象编程
  • C 语言实现面向对象编程

    万次阅读 多人点赞 2018-08-14 18:36:38
    C 语言实现面向对象编程 1、引言 面向对象编程(OOP)并不是一种特定的语言或者工具,它只是一种设计方法、设计思想。它表现出来的三个最基本的特性就是封装、继承与多态。很多面向对象的编程语言已经包含这三...
  • 首先java就是面向对象编程,所谓在java中万事万物皆对象,这是因为java中所有类的调用都是new出来的, 其次面向对象用到三大特性,即封装、多态、继承。 2、面向接口编程: 一个接口可以从三方面去考察:制定...
  • 简述面向函数编程和面向对象编程的区别? 什么时候使用面向函数编程?什么时候使用面向对象编程? 函数式编程,顾名思义,这种编程是以函数思维做为核心,在这种思维的角度去思考问题。 这种编程最重要的基础是λ...
  • JavaScript面向对象编程指南.pdf

    千次下载 热门讨论 2015-12-10 16:06:49
    JavaScript面向对象编程指南.pdf
  • 面向对象编程以及Python面向对象

    千次阅读 2015-11-04 22:59:14
    一、面向对象编程 面向对象编程(OOP)作为一种方式,相对于面向过程更加的贴近人的思维习惯。 面向对象是将一个整体问题划分为若干个模块,通过块与快之间的交流来解决问题;而面向过程编程是将一个问题按照...
  • C++-面向对象编程-000-面向对象

    千次阅读 2020-03-16 19:14:28
    C+±面向对象编程-000-2020-3-16
  • Java面向对象编程

    千次阅读 2018-07-02 13:16:14
    桂 林 理 工 大 学 实 验 报 告 班级 软件工程 学号 ****** 姓名 ***** 同组...实验名称 Java面向对象编程 日期 208年06 月07日 一、实验目的: 1. 理解 Java 语言是如何体现面向对象编程基本思想的; 2. 掌...
  • 面向对象编程和泛型编程

    千次阅读 2018-08-02 11:10:48
    C++不仅支持面向对象编程而且还支持泛型编程,那么我们是否在大脑中清晰的知道什么是面向对象编程和泛型编程吗?那面向过程编程了?? (1).面向对象编程简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,...
  • 面向过程编程 面向过程编程是一种以过程为中心的编程思想,分析出解决问题的步骤,然后用函数把这些...面向对象编程是将事物对象化,通过与对象进行通信来解决问题。面向对象编程,数据和对数据的操作是绑定在一起的。
  • C++是面向对象编程,C语言是面向过程编程。因此学习C++的第一件事就是要弄明白什么是面向过程编程,什么是面向对象编程。 之前学习的C语言是面向过程编程,回想一下C语言编程的过程。主函数,定义变量,调用函数...
  • OOP 面向对象编程

    千次阅读 2019-12-09 11:34:20
    //实际编码实现阶段则是面向对象编程[OOP] 在面向对象设计这一环节中,我们将需求描述转化为具体的类的设计。 这个环节的工作可以拆分为下面四个部分。 1. 划分职责进而识别出有...
  • 面向对象编程,再见!

    千次阅读 多人点赞 2018-10-07 17:30:00
    作为程序员,你是使用函数式编程还是面向对象编程方式?在本文中,拥有 10 多年软件开发经验的作者从面向对象编程的三大特性——继承、封装、多态三大角度提出了自己的疑问,并深刻表示是时候和面向对象编程说再见了...
  • 什么是面向过程编程?  面向过程编程(Procedure Oriented,OPP,面向对象程序设计)是一种以过程为中心的编程思想。“面向过程”也可称之为“面向记录”编程思想,他们不支持丰富的“面向对象...什么是面向对象编程
  • Java面向对象编程三大特征 - 继承

    千次阅读 多人点赞 2020-03-31 18:24:08
    本文关键字:Java、面向对象、三大特征、继承。继承是面向对象编程的三大特征之一,继承将面向对象的编程思想体现的更加淋漓尽致,允许类和类之间产生关联。
  • link和面向对象编程的取舍?现在不是提倡面向对象编程了么?那么用了link,查询变成过程化了,怎么体现多态呢?

空空如也

1 2 3 4 5 ... 20
收藏数 114,458
精华内容 45,783
关键字:

面向对象编程