js设计模式-面向对象 & UML类图介绍

OOP: Object Oriented Programming

面向对象编程

OOP概念

面向对象编程就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法)。这个对象我们称之为

JavaScript 是一种解释性的弱类型语言(无类语言),但是可以使用函数来模拟类。

ES5 创建对象

// 类,创建一个类
var People = function(name, age) {
    this.name = name;
    this.age = age;
}
People.prototype.eat = function() {
    alert(`${this.name} eat something`)
}

// 创建实例
let zhang = new People('zhang', 20);
zhang.eat();

ES6 创建对象

// 类 Class,创建一个类
class People {
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
    eat(){
        alert(`${this.name} eat something`)
    }
}

// 对象(实例),创建实例
let zhang = new People('zhang', 20);
zhang.eat();

OOP三要素:继承、封装、多态

  • 继承,子类继承父类

  • 封装,数据的权限和保密

  • 多态,同一接口不同实现

OOP 继承

// 父类
class People {
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
    speak(){
        alert(`My name is ${this.name}, age ${this.age}`)
    }
}
// 子类继承父类
class Student extends People {
  constructor(name, age, number) {
      super(name, age);
      this.number = number;
  }
  study() {
      alert(`${this.name} study`)
  }
}
// 实例
let xiaoming = new Student('xiaoming', 10, 'A1');
xiaoming.study();
console.log(xiaoming.number);
xiaoming.speak();
  • People 是父类,公共的,不仅仅服务于 Student

  • 继承可将公共方法抽离出来,提高复用,减少冗余

OOP 封装

  • public 完全开放

  • protected 对子类开放

  • private 对自己开放

  • (ES6尚不支持)

Javascript 是函数级作用域

var Book = function(id, name) {
    // 私有属性
    var num = 1;
    // 私有方法
    function checkId() {
      
    }
    // 特权方法
    this.getNum = function() {
      return num;
    }
    // 对象公有属性
    this.id = id;
    // 对象公有方法
    this.copy = function() {

    }
}

// 类静态公有属性(对象不能访问)
Book.isChinese = true;
// 类静态公有方法(对象不能访问)
Book.resetTime = function() {
  console.log('new Time');
};

Book.prototype = {
  // 公有方法
  isJSBook: false,
  // 公有方法
  display: function(){}
}

// test
var b = new Book(11, 'js设计模式');
console.log(b.getNum()); // 1
console.log(b.num); // undefined
console.log(b.id); // 11
console.log(b.isJSBook); // false
console.log(b.isChinese); // undefined

console.log(Book.isChinese); // true
Book.resetTime(); // 'new Time'

封装优点:

  • 减少耦合,不该外露的不外露

  • 利于数据、接口的权限管理

  • ES6目前不支持,一般认为 _ 开头的属性都是 private

OOP 多态

  • 同一个接口,不同表现

  • JS应用极少

  • 需要结合Java等语言的接口、重写、重载等功能

// 多态
function add() {
  var arg = arguments,
      length = arg.length;
  switch (length) {
    case 0:
        return 10;
    case 1:
        return 10 + arg[0];
    case 2:
        return arg[0] + arg[1];
  }
}

console.log(add()); // 10
console.log(add(5)); // 15
console.log(add(20, 30)); // 50
  • 保持子类的开放性和灵活性

  • 面向接口编程

  • (JS引用极少,了解即可)

OOP js的应用举例

  • jQuery 是一个 Class

  • $(‘p’) 是jQuery 的一个实例

class jQuery {
    constructor(selector){
        let slice = Array.prototype.slice;
        let dom = slice.call(document.querySelectorAll(selector));
        let len = dom ? dom.length : 0;
        for (let i = 0; i < len; i++) {
            this[i] = dom[i];
        }
        this.length = len;
        this.selector = selector || "";
    }
    append(node) {
    
    }
    addClass(name) {
    
    }
    html(data) {
    
    }
    // 此处省略若干API
}

window.$ = function(selector) {
    // 工厂模式
    return new jQuery(selector)
}

var $p = $('p');
console.log($p);
console.log($p.addClass)

OOP 的意义

为何使用面向对象?

  • 程序执行:顺序、判断、循环 - 结构化

  • 面向对象 - 数据结构化

  • 对于计算机,结构化的才是最简单的

  • 编程应该:简单&抽象

UML 类图-介绍

  • Unified Modeling Language 统一建模语言

  • 类图,UML 包含很多种图,和本课相关的是类图

  • 关系,主要讲解泛化和关联

  • 演示,代码和类图结合

画图工具

  • MS Office Visio

  • https://www.processon.com

类图,属性、方法

类名
+ public 属性名A:类型
# protected 属性名B:类型
- private 属性名C:类型
+ public 方法名A(参数1,参数2): 返回值类型
# protected 方法名A(参数1,参数2): 返回值类型
- private 方法名A(参数1,参数2): 返回值类型
// 父类
class People {
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
    eat(){
        alert(`${this.name} eat something`)
    }
    speak(){
        alert(`My name is ${this.name}, age ${this.age}`)
    }
}

以上js的类图是

People
+ name: String
+ age: Number
+ eat(): void
+ speak(): void

UML类图-关系

  • 泛化,表示继承

  • 关联,表示引用

class People {
    constructor(name, house) {
        this.name = name;
        this.house = house;
    }
    saySomething() {
    
    }
}

class A extends People {
    constructor(name, house) {
        super(name, house);
    }
    saySomething() {
        alert('I am A');
    }
}

class B extends People {
    constructor(name, house) {
        super(name, house);
    }
    saySomething() {
        alert('I am B');
    }
}

class House {
  constructor(city) {
      this.city = city;
  }
  showCity() {
      alert(`house in ${this.city}`);
  }
}

// 测试
let aHouse = new House('北京');
let a = new A('aaa', aHouse);
console.log(a); //a有房子

let b = new B('bbb');
console.log(b); /// b无房子