物件導向--基於類別與原型的範例


Posted by JingTeng on 2021-04-15

有鑑於,被朋友問到講得哩哩落落,寫個小 memo 給自己
本文著重在比較 Java class-based 與 JavaScript protoytpe-based

前言

OOP(物件導向程式)是什麼?
OOP = Object-oriented programming = 物件導向程式設計,是一種以物件設計程式設計的設計方法。
希望可以透過三大特性:繼承、封裝、多型,讓程式碼減少重複代碼並彈性地擴充,以及能零活調用組裝 。
遵守OOP開發原則(SOLID) 也能寫出更好維護的軟體。

本文以繼承特性為討論物件導向的範圍。

各語言如何支援物件導向?

class-based programming: Java

Java 是靜態(編譯)、強型別語言

學習 Java 的基礎:

  1. Everything in Java is an object
  2. "Class(類別)是 Object(物件)的藍圖,物件是類別的 Instance(實例)"

在 Java 中的物件必須先定義出 Class 才能夠創造出物件,而程式的運作需要透過 Object (Class Instance)。

從 Hello World 的範例裡看到,一行 print 指令需要被寫在一個 HelloWorld Class 檔案裡,編譯後執行。

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello! World!");
    }
}

Java 透過 new 與 extends 關鍵字來做到類別實例與繼承,Object Class 是所有的 Class 共同繼承的源頭。

// Class
public class Hero extends GameObject{
    public String name;

    public Hero(String name) {
        this.name = name;
    }
}

// Object
Hero heroAria = new Hero(Aria);
Hero heroBrant = new Hero(Brant);

我們已經為所有的 Hero 類別都定義了 name 屬性,如果之後想要修改所有物件的 name 屬性,例如加上 HERO 在名字前,就不需要一一修改。
這裡繼承的對象 class,沒有談到實體化的物件。

參考

  • Java 學習手冊

prototype-based programming: JavaScript

JavaScript 是動態(直譯/腳本)、弱型別語言

JavaScript 支援 OOP,也支援 FP(Functional Programming)

JavaScript 中則是使用 Prototype(原型)為基礎設計。

OOP 是一種設計典範,通常用於開發系統軟體。
因此,JavaScript、Python 這樣的腳本語言,OOP 的概念不是入門學習時首要的學習目標,許多教材會將 OOP 放在進階觀念裡。

回到繼承,JavaScript 是腳本語言,所以它並不用 Class 的方式實現繼承,而是透過原型鍊查找物件屬性。

講到繼承,JavaScript 就只有一個建構子:物件。每個物件都有一個連著其他原型(prototype)的私有屬性(private property)物件。原型物件也有著自己的原型,於是原型物件就這樣鏈結,直到撞見 null 為止:null 在定義裡沒有原型、也是原型鏈(prototype chain)的最後一個鏈結。

我從 Java 進入 JavaScript 在學習 prototype 的時候曾產生混亂,不明白為什麼用建構式定義物件時使用 function 關鍵字、為什麼 new 一個函式會跑出物件。(因為我們定義的這個函式是個建構子)

傳統的 OOP 都是先定義了類別,接著在建立物件實例之後,在類型上定義的所有屬性與函式均複製到此實例。但 JavaScript 不會複製這些屬性與函式,卻是在物件實例與其建構子之間設定連結 (原型鍊中的連結),只要順著原型鍊就能在建構子之中找到屬性與函式。
MDN 物件原型

function f() {
  return 2;
}

// 從 Function.prototype 繼承的函式,含有諸如 call、bind……之類的方法
// f ---> Function.prototype ---> Object.prototype ---> null
function Graph() {
  this.vertices = [];
  this.edges = [];
}

Graph.prototype = {
  addVertex: function(v) {
    this.vertices.push(v);
  }
};

var g = new Graph();
// g 是個有著「vertices」與「edges」屬性的物件。
// 在執行 new Graph() 時 g.[[Prototype]] 是 Graph.prototype 的值。

累了,寫到這裡好了。
有誤歡迎糾正。

參考


#程式設計







Related Posts

在迴圈內依條件判斷新增元素

在迴圈內依條件判斷新增元素

如何使用 Markdown 撰寫文章?

如何使用 Markdown 撰寫文章?

PHP、MySQL 語法基礎

PHP、MySQL 語法基礎


Comments