Programming

物件導向程式設計 object-oriented-programming (OOP)

物件導向程式設計 object-oriented-programming (OOP) 是一種程式語言模型 (programming language model),程式需要圍繞著物件而不是圍繞著 function 和邏輯。

Object-oriented programming (OOP) is a programming language model in which programs are organized around data, or objects, rather than functions and logic. An object can be defined as a data field that has unique attributes and behavior.

當你看到 class 跟 object 可以把它們看成是相同的東西,因為英文通常會寫成**一類物件 (a class of objects)**。

物件裡面可以包含兩個東西:

  • 唯一的屬性 unique attributes
  • 操作屬性的行為 behavior that manipulate it

物件導向裡面,行為又可以稱作為方法 method

定義

物件導向有四個基本的原則,分別是:

封裝 Encapsulation

封裝是一個物件導向的概念,它將屬性 (data) 和操作屬性的行為 (function) 綁在一起,同時避免外部的干擾和誤用。data hiding 能夠把不需要透露給外部的資料隱藏起來,讓外部無法存取。

Encapsulation is an Object Oriented Programming concept that binds together the data and functions that manipulate the data, and that keeps both safe from outside interference and misuse.

抽象 Abstraction

抽象是一種設計 programming 的技術,需要將介面 (interface)實作 (implementation) 的分離。簡單來說就是設計 API 的介面。在 C++ 需要把設計好的介面放在 public 底下。

Abstraction is a programming (and design) technique that relies on the separation of interface and implementation.

繼承 Inheritance

在定義物件時,子類 (subclass) 可以繼承一個或多個物件 classes。

Inheritance is the concept that when a class of objects is defined, any subclass that is defined can inherit the definitions of one or more general classes

多型 Polymorphism

在物件被繼承的時候,允許變數、函數或物件具有多於一種形式。相關的概念有 dynamic binding,在 C++ 裡面需要用到 virtual

Polymorphism is the characteristic of being able to assign a different meaning or usage to something in different contexts - specitically, to allow an entity such as a variable, a function or, an object to have more than one form.

比較 Encapsulation vs Abstraction

看完定義以後,會不會覺得封裝 (Encapsulation) 跟抽象 (Abstraction) 的定義有點類似:

  • 封裝強調的是綑綁 data 的機制,和使用這些 data 的 function

Data encapsulation is a mechanism of bundling the data, and the functions that use them

  • 抽象強調的是暴露介面和隱藏實作細節的機制

Data abstraction is a mechanism of exposing only the interfaces and hiding the implementation details from the user.

Example Code

以下是程式碼範例:

Reference

C++ Friend Class and Function

Friend

將另一個 class 設成 firend,可以讓該 class 存取自己 private data,參考底下的範例:

A 將 B 設成 firend,則物件 B 裡 private、protected、public function 都可以存取該物件 A 裡的 private、protected、public 的資料。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream> 
class A {
private:
int a;
public:
A() { a=0; }
friend class B; // Friend Class
};

class B {
private:
int b;
public:
void showA(A& x) {
// In B, you can access private member of A by adding friend
std::cout << "A::a = " << x.a;
}
};

int main() {
A a;
B b;
b.showA(a);
return 0;
}

上面的程式碼代表著 A 的 private data 可以給 B 使用。

A 將某個 function 設成 firend,則該 function 都可以存取該物件 A 裡的 private、protected、public 的資料。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
class A {
int a;
public:
A() {a = 0;}
friend void showA(A&); // global friend function
};

void showA(A& x) {
// In this function, you can access private member of A by adding friend
std::cout << "A::a=" << x.a;
}

int main() {
A a;
showA(a);
return 0;
}

上面的程式碼代表著 A 的 private data 可以給 showA function 使用。

friend function 可以放在 class 的任何地方,不受關鍵字 private、protected、public 的限制。

Reference

Css 排版歷史

排版歷史

在 css 的戰國時代裡,大部分在網路上找到的排版方法,大多是 float 跟 inline-block 這兩種,沒聽課的話還真的不知道排版的歷史:

  • table
  • float
  • inline-block
  • flex
  • grid

之後會想來玩玩看 flex 跟 grid,反正是自己的部落格,IE8 以下的用戶就不好意思了。用 table 排版已經太舊太久遠就先不管。然而現在最常用的兩種排版方法 float 跟 inline-block ,還是會有一些問題存在:

閱讀全文

Ruby Regexp MatchData

=~ Operator

回傳比對的位置到的起始位置,沒有比對到則回傳 nil

1
2
/cat/ =~ 'hiakiicat'               # => 6
/tac/ =~ 'hiakiicat' # => nil

match method

有 match 到會回傳 MatchData,如果沒有 match 到則會回傳 nil。

1
2
m = /akii(.+)$/.match('hiakiicat')
# => #<MatchData "akiicat" 1:"cat">

括號起來的資料 (...) 才會另外存成一個值。如果不想要另外存成一個值,可以在括號裡面打 (?:...)

獲取資料:

  • m[0] 為 match 到的所有資料。
  • m[1] 為第一個括號裡面所比對到的資料,以此類推。
1
2
3
m[0]            # => "akiicat"
m[1] # => "cat"
m[2] # => nil

閱讀全文

Ruby on Rails long string id

之前有講到使用 UUID 當作 primary key 的方法,因為 postgresql 有提供 uuid,可以直接拿來使用。

接下來的這個方法適用於所有的資料庫,在物件儲存之前先給定它的 id,如此一來就能定義我們所想要的內容了。

先隨便用鷹架產生點東西:

1
rails g scaffold book title

加上 id: :string 讓 id 的型態為 string。

1
2
3
4
5
6
7
8
9
# db/migrate/20170218105724_create_books.rb
class CreateBooks < ActiveRecord::Migration[5.0]
def change
create_table :books, id: :string do |t|
t.string :title
t.timestamps
end
end
end

閱讀全文

Ruby on Rails 5 dynamic subdomains

一個使用者有名字 name 還有自己網頁的子網域 subdomain,我們想要的結果是讓每一位使用者有自己的子網域,而且還可以隨時更改。

假設現在有個使用者是 User.create(name: "akii", subdomain: "akiicat"),在 rails 預設 show 頁面會是 http://localhost:3000/users/1,但我們想把網址變成個人的子網域 http://akiicat.localhost:3000

接下來會用鷹架建立使用者來做示範:

1
2
rails g scaffold user name subdomain
rake db:migrate

修改 routes.rb,加上首頁,然後把 show 的頁面加上 subdomains 的限制。

1
2
3
4
5
6
7
8
# config/routes.rb
Rails.application.routes.draw do
resources :users
constraints subdomains: /.+/ do
get '', to: 'users#show'
end
root to: 'users#index'
end

閱讀全文

Ruby on Rails 5 api subdomain

為了要 demo api subdomain 的頁面是否能夠運作,這邊用鷹架隨便建立個東西。

1
2
rails g scaffold api::v1::books title
rake db:migrate

使用 constraints 限制 subdomain: 'api'

然後用 scope module: 'api' 加上 app/controllers/api 這個資料夾。

1
2
3
4
5
6
7
8
9
10
# config/routes.rb
Rails.application.routes.draw do
constraints subdomain: 'api' do
scope module: 'api' do
namespace :v1 do
resources :books
end
end
end
end

閱讀全文

Ruby on Rails callback 筆記

可用的 callback

以下是 Active Record 可用的 callback,依照執行順序排序:

新建物件

1
2
3
4
5
6
7
8
9
before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit/after_rollback

更新物件

1
2
3
4
5
6
7
8
9
before_validation
after_validation
before_save
around_save
before_update
around_update
after_update
after_save
after_commit/after_rollback

閱讀全文

Ruby on Rails foreign key must exist 的問題

rails 在這次的更動之後,如果 belongs_to 的 foreign key 不存在的時,會產生驗證錯誤。

1
2
3
4
5
6
7
8
9
class Author < ActiveRecord::Base
end

class Book < ActiveRecord::Base
belongs_to :author
end

book = Book.create(title: "book")
book.errors.full_messages # => ["Author must exist"]

上面的例子可以看到,我們沒辦法建立 Book 的紀錄。

options

  • required: 如果設為 true 的話,會驗證關聯是否存在。在 rails 5 預設為 true
  • optional: 如果設為 true 的話,不會驗證關聯是否存在。

上面兩個選項都是驗證關聯本身,不是驗證 foreign key 的 id。

閱讀全文

Ruby on Rails 探索 inverse_of

inverse_of

主要功能會去通知對方自己的狀態,可以解決物件不同步的問題。

在 belongs_to 裡的 :inverse_of 會去找尋所對應的 has_one has_many 上相同的名稱,來通知他們之間的關係。

在 has_one has_many 裡的 :inverse_of 會去找尋所對應的 belongs_to 上相同的名稱,來通知他們之間的關係。

如果沒有寫 :inverse_of 這參數,rails 會使用 heuristic algorithm 去猜測名稱,但在如果不是使用標準名稱的話會失效。

Without inverse_of

沒有 :inverse_of 會發生物件不同步的問題,可以看以下的範例:

1
2
3
4
5
6
7
class Author < ActiveRecord::Base
has_many :books
end

class Book < ActiveRecord::Base
belongs_to :author, inverse_of: false
end

閱讀全文