美文网首页
浅谈“类”

浅谈“类”

作者: zhangwinwin | 来源:发表于2018-05-22 17:31 被阅读0次

面向对象编程强调的是数据和操作数据的行为本质上是互相关联的,因此好的设计就是把数据以及和它相关的行为封装起来。

举例来说,用来表示一个单词或者短语的一串字符通常被称为字符串。字符是数据。但关心的往往不是数据是什么,而是可以对数据做什么,所以可以应用在这种数据上的行为(计算长度、添加数据等等)都被设计成String类的方法。

所有的字符串都是String类的一个实例,包含字符数据和我们可以应用在数据上的函数。还可以使用类对数据结构进行分类,可以把任意数据结构看作范围更广的定义的一种特例。

汽车(Car)可以被看作交通工具(Vehicle)的一种特例,后者是更广泛的类。

Vehicle的定义可能包括推进器(比如引擎)、载人能力等,这些都是Vehicle的行为。对Vehicle中定义的是所有类型的交通工具都包含的东西。

对不同的交通工具重复定义“载人能力”是没有 意义的。相反,只需在Vehicle中定义一次,定义Car时,只有声明它继承了Vehicle的这个基础定义就行。Car的定义就是对通用Vehicle定义的特殊化。
这就是类、继承和实例化。类的另一个核心概念是多态:弗雷的通用行为可以被字类用更特殊的行为重写。实际上,相对多态允许我们重写行为中引用基础行为。

构造函数:类实例是由一个特殊的类方法构造的,这个方法命通常和雷明相同,被称为构造函数.思考下列伪代码

class CoolGuy {
       specialTrick = nothing
       CoolGuy( trick ) {
              specialTrick = trick
       } showOff() {
              output( "Here's my trick: ", specialTrick)
       }
}

可以调用类构造函数来生成一个CoolGuy实例:
Joe = new CoolGuy('Hi') ; Joe.showOff()// HI

1、类的继承
在面向类的语言中,先定义一个类,然后定义一个继承前者的类。后者通常被称为‘字类’,前者通常被称为‘父类’。父类和字类并不是实例。
思考下面关于类继承的伪代码:

class Vehicle{
    engines = 1
        ignition(){
        output("Turning on my engine.");
    }
    drive(){
        ignition();
        output("Steering and moving forward!")
    }
}
class Car inherits Vehicle{
    wheels = 4
        drive(){
        inherited : drive()
        output("Rolling on all ", wheels, " wheels!")
    }
}
class SpeedBoat inherits Vehicle{
    engines = 2
        ignition(){
        output("Turning on my ", engines, " engines.")
    }
    pilot(){
        inherited : drive()
        output("Speeding through the water with ease!")
    }
}

Car重写了继承父类的drive()方法,但之后Car调用了inherited:drive()方法,这表明Car可以引用继承来的原始drive()方法。pilot()方法同样引用了原始drive()方法。这个技术被称为多态。在本例中,更好的说法是相对多态。

在许多语言中可以使用super来代替本例中的inherited:,它的含义是”超类“,表示当前类的父类/祖先类。

2、混入
在继承或者实例化时,JavaScript的对象机制并不会自动执行复制行为。简单来说,JavaScript中只有对象并不存在可以被实例化的类。一个对象并不会被复制到其他对象,它们会被关联起来。由于在其他语言中类表现出来的都是复制行为,因此JavaScript开发者也想出一个方法来模拟类的复制行为,就是混入。

2.1、显示混入
回顾前面提到的Vehicle和Car。由于JavaScript不会自动实现Vehicle到Car的复制行为,所以要手动实现复制功能。这个功能在许多库和框架中被称为extend(),为了方便我们称之为mixin()。

// 非常简单的 mixin(..) 例子 :
function mixin(sourceObj, targetObj){
    for (var key in sourceObj){
        // 只会在不存在的情况下复制
        if (!(key in targetObj)) {
            targetObj[key] = sourceObj[key];
        }
    }
    return targetObj;
}
var Vehicle ={
    engines : 1,
    ignition : function (){
        console.log("Turning on my engine.");
    },
    drive : function (){
        this.ignition();
        console.log("Steering and moving forward!");
    }
};
var Car = mixin(Vehicle,{
        wheels : 4,
        drive : function (){
            Vehicle.drive.call(this);
            console.log(
                "Rolling on all " + this.wheels + " wheels!");
        }
} );

现在Car就有一份Vehicle属性和函数的副本。从技术角度来说,函数实际上没有被复制,复制的是函数引用。

这条语句:Vehicle.drive.call(this)。这就是显示多态。JavaScript(在ES6之前)并没有相对多态机制。所以由于Car和Vehicle中都有drive()函数,为了指明调用对象,必须使用绝对引用。

现在来分析mixin()原理。它会遍历sourceObj的属性,如果targetObj没有这个属性就会进行复制。复制操作完成后,Car就和Vehicle分离了,向Car中添加属性不会影响Vehicle,反之亦然。

2.2、寄生继承:是显示混入模式的一种变体,既是显式的又是隐式的。
下面是它的工作原理:

//“传统的 JavaScript 类” Vehicle
function Vehicle(){
    this.engines = 1;
}
Vehicle.prototype.ignition = function (){
    console.log("Turning on my engine.");
};
Vehicle.prototype.drive = function (){
    this.ignition();
    console.log("Steering and moving forward!");
}; //“寄生类” Car
function Car(){
    // 首先, car 是一个 Vehicle
    var car = new Vehicle();
    // 接着我们对 car 进行定制
    car.wheels = 4;
    // 保存到 Vehicle::drive() 的特殊引用
    var vehDrive = car.drive;
    // 重写 Vehicle::drive()
    car.drive = function (){
        vehDrive.call(this);
        console.log(
            "Rolling on all " + this.wheels + " wheels!");
        return car;
    }
var myCar = new Car();
myCar.drive();
// Turning on my engine.
//Steering and moving forward

2.3、隐式混入
思考下列代码:

var Something ={
    cool : function ()
    {
        this.greeting = "Hello World";
        this.count = this.count ? this.count + 1 : 1;
    }
};
Something.cool();
Something.greeting; // "Hello World"
Something.count; // 1
var Another ={
    cool : function () {
        // 隐式把 Something 混入 Another
        Something.cool.call(this);
    }
};
Another.cool();
Another.greeting; // "Hello World"
Another.count; // 1(count 不是共享状态)

通过在构造函数调用或者方法调用中使用Something.cool.call(this),实际上”借用“了函数Something.cool()并在Another的上下文中调用了它。最终结果是Something.cool()中的赋值操作都会应用在Another对象上而不是Something对象上。因此我们把Something的行为”混入“到了Another中。

相关文章

  • 浅谈“类”

    面向对象编程强调的是数据和操作数据的行为本质上是互相关联的,因此好的设计就是把数据以及和它相关的行为封装起来。 举...

  • iOS 关于基类

    参考文档:浅谈 : iOS工程中哪些需要建立基类(MVC)

  • 浅谈架构-----类

    当前流行的软件架构,无论理论多么的高深,思想多么先进,最终都会落实到一个个的功能类上面去,当前我们对编程的思...

  • 浅谈ThreaLocal类

    ThreadLocal是什么? 话不多说,首先直接给上JDK的解释: This class provides th...

  • 浅谈 类库

    首先我们要知道 什么是 类 库?库是程序代码的集合,是共享程序代码的一种方式 而我们根据源代码的公开情况,库可以分...

  • 浅谈javascript常用类

    浅谈javascript常用类 1,Math(数学对象)常用方法 1,ceil() 向上舍入 返回大于等于x,...

  • python面向对象编程(3)

    类设计浅谈 1.抽象类设计 抽象方法:在编写class语句中,若有存在未定义或是未实现的或是@abstractme...

  • 浅谈安卓开发中context用到的装饰模式

    浅谈安卓开发中context用到的装饰模式 一、UML图 说明:Context类是最根部的抽象类,不实现具体的功能...

  • 2020-07-02

    浅谈 浅谈模块设计宏内核 浅谈接口设计Flags 浅谈稳定性设计重试 浅谈人员业务结构设计矩阵式 浅谈接口设计 |...

  • JAVA NIO之浅谈内存映射文件原理与DirectMemory

    转自 [Java][IO]JAVA NIO之浅谈内存映射文件原理与DirectMemory Java类库中的NIO...

网友评论

      本文标题:浅谈“类”

      本文链接:https://www.haomeiwen.com/subject/tgfkjftx.html