面向对象四大特征

81 篇文章 7 订阅

面向对象四大特征

一、抽象

概念

  • 抽象主要是隐藏方法的实现,让调用者只关心有哪些功能而不是关心功能的实现。
  • 抽象可以提高代码的可扩展性和维护性,修改实现不需要改变定义,可以减少代码的改动范围。

代码展示

// 接口
interface IStorage {
    save(key: string, value: any): void;
    read(key: string): any;
}

// userinfo类
class UserInfo {
    constructor(public name: string, public storage: IStorage) {}
    save() {
        this.storage.save('userinfo', JSON.stringify(this));
    }
    read() {
        return this.storage.read('userinfo');
    }
}

// LocalStorage类实现IStroage接口
class LocalStorage implements IStorage {
    save(key: string, value: any): void {
        localStorage.setItem(key, value);
    }
    read(key: string) {
        return localStorage.getItem(key);
    }
}

let local = new LocalStorage();
let userinfo = new UserInfo('zhufeng', local);
console.log(userinfo.name);

代码解释

现在代码里实现的是把传到UserInfo的信息存入到本地存储里。

  • 在代码里,我们有一个IStorage接口,这个接口又两个方法,save() 存,read() 取。
  • 然后我们定义了一个LocalStorage类,让它去实现了IStroage接口。
  • 我们调用的时候只需要 new 一个 LocalStorage 的实例,然后连带着信息传给Userinfo即可。

重点来了:

看了我上面写的概念、代码、解释,你可能还是晕乎乎的。你的问题可能还是:什么是抽象

别急,我们对着概念一步一步来看:

  1. 抽象主要是隐藏方法的实现,让调用者只关心有哪些功能而不是关心功能的实现。

    • 在上面的代码里,很明显,调用者是 UserInfo类,UserInfo类 调用 storage 存储功能时,它需要知道 LocalStorage 怎么实现的吗?它不需要知道,他只需要知道通过 storage打点可以拿到save或read进行存储或读取 就行了。
  2. 抽象可以提高代码的可扩展性和维护性,修改实现不需要改变定义,可以减少代码的改动范围。

    • 这里面的重点句子是:扩展或修改的时候我们只需要改动实现,不需要改变定义。
    • 上面代码中的实现很明显是 LocalStorage

    如果接下来我们有一个需求,我们进行一个MySQL的存储【模拟】,那我们怎么扩展我们的代码呢?

    // MySqlStorage类实现IStroage接口
    class MySqlStorage implements IStorage {
        save(key: string, value: any): void {
            // mysql.setItem(key,value);
        }
        read(key: string) {
            // return mysql.getItem(key);
        }
    
    }
    let mysqlStorage = new MySqlStorage();
    let mysql = new UserInfo('mysql',mysqlStorage);
    

    我们只需要定义一个MySqlStorage类实现即可,不用去改动UserInfo类的定义。

调用者和功能实现之间耦合度降低,调用者不需要知道怎么功能实现,改了功能也不用去通知调用者或者修改调用者,这就是抽象。

二、封装

概念:

  • 把数据封装起来 , 减少耦合,不该外部访问的代码不要让外部访问。
  • 封装利于数据的接口权限管理 。
  • 封装仅暴露有限的必要接口,可以提高类的易用性。

实现:

  • public:共有修饰符,可以在类内或者类外使用public修饰的属性或者行为,默认修饰符。
  • protected:受保护的修饰符,可以在本类和子类中使用protected修饰的属性和行为。
  • private:私有修饰符,只可以在类内部使用private修饰的属性和行为。

代码展示:

class Animal {
    // 公有:此属性可以在本类,子类和其他类中访问
    public name: string;
    // 受保护的:此属性可以在本类和子类中访问,其他类不行
    protected age: number;
    // 私有:此属性只能在本类中访问,子类和其他类都不行。
    private weight: number;

    constructor(name: string, age: number, weight: number) {
        this.name = name;
        this.age = age;
        this.weight = weight;
    }
}

class Person extends Animal {
    // 账户余额 私有的,只有自己可以访问
    private balance: number;

    constructor(name: string, age: number, weight: number, balance: number) {
        super(name, age, weight);
        this.balance = balance;
    }

    getName() {
        return this.name;
    }

    getAge() {
        return this.age;
    }

    getWeight() {
        return this.weight; // weight私有,无法访问
    }
}

let p1 = new Person('zhufeng', 10, 100, 1000);
p1.name;
p1.age; // age受保护,不可访问
p1.weight; // weight私有,不可访问

代码解释:

上面封装的都是以 属性 来举例,对于类内部的方法来说同样可以用修饰符修饰。

  • Person类继承了Animal类,但是Person无法访问Animal类中的 weight 属性,因为 weight 属性 private 修饰。
  • 我们new 了一个Person的实例,然后去访问 age,我们发现 age 不可访问,因为 protected修饰,protected修饰的属性或方法只能在本类和子类中访问。

封装的概念较为简单,有代码做理解,这里就不过多赘述了。

三、继承

概念:

  • 继承主要的用处是实现代码复用。

  • 继承可以把父类和子类的公共方法抽象出来,提高复用,减少冗余。

    缺点:

    • 过度使用继承或者说继承层次过深会导致代码可读性变差,可维护性变差,子类和父类高度耦合,修改父类的代码会直接影响到子类。

代码展示:

class Animal {
    public name: string;
    constructor(){
        this.name = name;
    }
    eat(){
        console.log('吃东西');
    }
}

let animal = new Animal();
animal.eat();

class Dog extends Animal {

}

let dog = new Dog();
dog.eat();

代码解释:

  • Dog类继承自Animal类,Dog也就拥有了Animal类所有的方法和属性。
  • 说到这里,我们可能就要联系一下另外一个特征:面向对象——封装 了,这个可以自己体会一下。

**题外话:**现在我们一般用的框架,例如:Angular,组件之间也是可以继承的,感兴趣的同学可以尝试尝试组件之间的继承。

四、多态

概念:

  • 多态是指,子类可以替换父类。
  • 保持子类的开放性和灵活性,可以重写父类的方法。
  • 实现面向接口编程。

代码展示:

class Animal {
     speak() {
         throw new Error('此方法必须由子类实现');
     }
}

// 子类必须实现speak方法,不实现就报错
class Dog extends Animal {
    speak() {
        console.log('汪汪汪');
    }
}

class Cat extends Animal {
    speak() {
        console.log('喵喵喵');
    }
}

function talk(animal: Animal) {
    animal.speak();
}

talk(new Dog()); //汪汪汪
talk(new Cat()); //喵喵喵

代码解释:

  • Cat类和Dog类都集成了Animal类,同时也都重写了Animal类的speak方法。

    子类对父类的方法重写是必须的,不重写就会出错。

  • 这种情况下,其实Animal类还有另一种写法,使用abstract关键字【抽象类】:

    abstract class Animal {
        abstract speak(): void;
    }
    

对于父类的方法,子类可以有各种各样的实现,这就是多态。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值