初心者筆記

[Git] Common Commnads

Squash your latest commits into one

Step 1

git rebase -i [hash code of the base commit]

Step 2 - you will see the commits after that base. These are the commits you want to squash.

pick b4928fe Add a cool feature
pick 9843da2 Fix up some bugs
pick f1c23dd Change some styles in the feature

Step 3 - pick one and squash the other commits to it.

pick b4928fe Add a cool feature
squash 9843da2 Fix up some bugs
squash f1c23dd Change some styles in the feature

Checkout a commit with a tag name and put that commit in a new branch

git checkout [tag name] -b [branch name]

Delete branches

Locally

git branch -D [local_branch_name]

Remotely

git push origin --delete [remote_branch_name]

Fetch pull request to local for runnning

(TBA)

Stash!

Temporally save diff in a stack

git stash

Take out the last stashed diff

git stash pop

Give up the last stashed diff

git stash drop

[General] 關於版本號

一般常見的版本號格式為 major.minor.(build), ex. 1.0.2

major

代表主要版本號,一個軟體在Alpha, Beta測試階段時通常是0,例如 0.0.1, 0.0.2, 0.2.1...
進入正式版本major就會跳到1,例如某某軟體終於在聖誕節前出了正式版啦!版本號為1.0.2
major變動通常是大變動(大便丼?!),例如整個API的改變,通常需要使用者完全刪除軟體之後再重新安裝

minor

小變動(小便丼?!),可能是新增了一個feature,例如某聊天軟體新增了動態貼圖功能,就會從1.6.x升到1.7.x

build

最後build的版本(可有可無),代表著可能是修了一些小bug

[Fun] What Is MISC?

misc means miscellaneous
五花八門的意思!例如在相簿分類的時候可以創misc這樣一個資料夾放無法歸類的相片。

[Linux] 有用簡單指令

  • Compress file/folder
    $ tar -jpcv -f [file name and location after compressing] [file or folder to compress]
    
  • Check the compressed file
    $ tar -jtv -f [file to be checked]
    
  • Unpack the compressed file
    $ tar -jxv -f [file to be unpacked] -C [directory to be unpacked to]
    
  • Reload the configuration file when it is modified
    $ resource ~/.bashrc
    
    or
    $ . ~/.bashrc
    
  • Find a file or folder
    $ find [directory] -name [file or folder name]
    
  • Write command result to a file (>, >>)
    $ [command] > [file] // write correct std output to file (overwrite)
    $ [command] >> [file] // write correct std output to file (continue inserting)
    $ [command] 2> [file] // write error output to file
    $ [command] > [file1] 2> [file2] // write correct std output to file1 and write error output to file2
    $ [command] > [file] 2> &1 // write both correct and error output to file
    
  • Pipeline's friends (cut & grep)

    $ [command] | cut -d ":" -f 3 // use ":" to split the standard output string as an array and select the third element in the array
    $ [command] | cut -c 12- // only show the characters after the 12th char
    $ [command] | grep 'root' // show lines that contain the word 'root'
    $ [command] | grep -v 'root' // show lines that "do not" contain the word 'root'
    $ [command] | grep -i 'root' // show lines that contain the word 'root' (do not care about the upper/lower case)
    

    ( There are more like "sort", "uniq", "wc")

  • Append a result to a file

    $ ls | tee file1 // overwrite the result to file1
    $ ls | tee -a file1 // append the result to file1
    
  • Delete/Replace a char

    $ last | tr -d ":" // delete all the ":" from the result of last
    $ last | tr '[a-z]' '[A-Z]' // change small letters into big letters in the result from last
    
  • grep, egrep, sed, awk

Let's do something with tis sample text file.

player_list.txt
Name:Occupation:Age:Role:Score
George:SE:26:Wizard:349
Libby:Sales:24:Assasin:366
Jei:Designer:25:Knight:220

Here we just execute some commna commands

Greo the line the contains the keyword(s)
$ cat player_list.txt | grep 'Name'
Name:Occupation:Age:Role:Score
$ cat player_list.txt | egrep 'Name|Jei'
Name:Occupation:Age:Role:Score
Jei:Designer:25:Knight:220
Replace the 3rd line to Kevin:Student:25:Archer:253
$ cat player_list.txt | sed '3c Kevin:Student:25:Archer:253'
Name:Occupation:Age:Role:Score
George:SE:26:Wizard:349
Kevin:Student:25:Archer:253
Jei:Designer:25:Knight:220
List the data with a very elegent layout
$ cat player_list.txt | awk'BEGIN {FS=":"} NR==1 {printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,$5} NR>=2 {printf "%10s %10s %10d %10s %10d\n",$1,$2,$3,$4,$5}'
      Name Occupation        Age       Role      Score
    George         SE         26     Wizard        349
     Libby      Sales         24    Assasin        366
       Jei   Designer         25     Knight        220

[General] Dependency Injection

看本篇文章前,建議先了解以下Java/物件導向編程(OOP)的基礎概念
1. class
2. object (an instance of a class)
3. constructor of a class
4. argument(s) of a funciton (or method)

What?

首先我們要了解什麼是dependency

public class MyDao {
  protected DataSource dataSource = new DataSourceImpl("driver", "url", "user", "password");
  
  //data access methods...

  public Person readPerson(int primaryKey) {...}
  }
}

在上面這個例子,MyDao它扮演著Database Access Object(DAO)的角色,當作我們聯絡某個database的橋樑,這個class有一個variable叫做dataSource,他的值是DataSourceImpl產生的一個instance,在這樣的情況下我們可以說MyDao depends on DataSourceImpl 還有它的四個argument("driver", "url", "user", "password"這四個字串)

Why?

也因為這樣的依賴性,當我們想要改變MyDao聯絡的database所處的位置,我們要改變的是new DataSourceImpl("driver", "url", "user", "password")中的"url"這個字串,所以需要動手將MyDao大括弧裡面的這一小段程式碼做修正,大概像下面這樣:

protected DataSource dataSource = new DataSourceImpl("driver", "url-new", "user", "password");

這樣直接改程式碼存在一個風險,如果我們需要一百個MyDao來連結一百個不一樣的database的位置,那我就要寫一百個像這樣的class,有沒有覺得很沒效率?
因此我們需要一個比較聰明的方法 - dependency injection!

How?

其實只要把MyDao稍微改一下,就可以解決這樣的問題

public class MyDao {
  protected DataSource dataSource = null;
  // constructor of MyDao

  public MyDao(String driver, String url, String user, String password) {
    this.dataSource = new DataSourceImpl(driver, url, user, password);
  }
  
  //data access methods...

  public Person readPerson(int primaryKey) {...}
  }
}

我們把原本已經寫死的四個argument改放在MyDao的constructor裡,所以當我們在創立MyDao的instance的時候(new MyDao()),就可以在這裡設定dataSource的參數(也就是driver, url, user, password)。

這樣我們只要寫一個class就可以創立100個不同的instnace(不用笨笨的寫100個class)

其實我們可以做得更徹底一點,在constructor放進DataSource這個class的參數,這樣做我們就不會被限制一定要用DataSourceImpl來產生DataSource的instance

public class MyDao {
    protected DataSource dataSource = null;
  public MyDao(DataSource dataSource){
  this.dataSource = dataSource;
  }

    //data access methods...

  public Person readPerson(int primaryKey) {...}
}

像這樣把MyDao所倚賴的DataSourceImpl和它的argument拉到外層來,由外部去定義,這樣的技巧就叫dependency injection,一種把依賴的物件注射到裡層的概念。

More - Dependency Injection Chaining

不只一層的相依關係,就有機會用到chaining的概念,參考以下程式

public class MyBizComponent{
    public void changePersonStatus(Person person, String status){
    MyDao dao = new MyDao( new DataSourceImpl("driver", "url", "user", "password"));
    Person person = dao.readPerson(person.getId());
    person.setStatus(status);
    dao.update(person);
  }
}

在這個例子我們可以看到MyBizComponent depends on MyDao. 而MyDao depends on DataSourceImpl,像上面這樣把變數寫死在裡層就會存在寫一百次的風險。

我們一樣把MyDao拉出來放在MyBizComponent的constructor裡面,即可解決

public class MyBizComponent{
  protected MyDao dao = null;
  public MyBizComponent(MyDao dao){
    this.dao = dao;
  }
  public void changePersonStatus(Person person, String status){
    Person person = dao.readPerson(person.getId());
    person.setStatus(status);
    dao.update(person);
  }
}

下次我們要產生一個MyBizComponent的時候,只要像鎖鏈般去注射即可

MyBizComponent myBizComponent = new MyBizComponent( new MyDao( new DataSourceImpl("driver", "url", "user", "password")));

參考文獻/Reference: Dependency Injection

[Android] How Can Thread Update Layout

在Android,我們不能直接在thread實作的run()這個moethod裡面,直接對layout介面改變
舉一個錯誤的例子:

private TimerTask timerTask = new TimerTask() {
    public void run() {
        txtClock.setText("00:00"); //在這裡更改layout介面是違法的喔!

    }
};

解決方法:

請使用Handler接收由thread裡面傳出的訊息Message

private TimerTask timerTask = new TimerTask() {
    public void run() {
        Message message = new Message();
        message.what = 1; //送給Handler的訊息, 讓Handler去判斷要做甚麼事

        mHandler.sendMessage(message); //mHandler在下一段程式碼define

    }
};

然後再由Handler接收訊息

private Handler mHandler = new Handler() {
    public void handlerMessage(Message msg) {
        super.handlerMessage(msg);
        switch(msg.what){
        case 1: //Handler就會知道是哪個thread送過來的

            //這裡放要做的事情(程式碼)

            break;
        }
    }
};