2013年12月15日 星期日

Android 開發 (七) DB 的使用介紹

在Android中要使用DataBase的功能,可以實作 SQLiteOpenHelper 或 SQLiteDatabase 接著只需在裡面使用相關的sql command即可 在這邊就稍微介紹一下該如何下指令



interface DAO_DB
{
 public void createTable();
 public void insertData(Object obj);
 public void deleteData(Object obj);
 public void updateData(Object obj);
 public void FindAllData();
 public void FindLastID();
 public void close();
}
public class DBHelper extends SQLiteOpenHelper implements DAO_DB{
 private SQLiteDatabase dbDatabase;
 private String TABLE_NAME = "MyTab";
 
 public DBHelper(Context context) {
  super(context, "TED_DE", null, 1);
  // TODO Auto-generated constructor stub
 }


 @Override
 public void onCreate(SQLiteDatabase db) {
  // TODO Auto-generated method stub
  dbDatabase = db;
  createTable();
 }

 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void createTable() {
  // TODO Auto-generated method stub
  String cmd = "CREATE TABLE " + TABLE_NAME + " ("
    + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
    DBColumns.NAME + " TEXT, " +
    DBColumns.TEL + " TEXT, " +
    DBColumns.EMAIL + " TEXT);"; 
  dbDatabase.execSQL(cmd);
 }

 @Override
 public void insertData(Object obj) {
  HashMap<String, String> map = (HashMap<String, String>)obj;
     String sql = "INSERT INTO "+ TABLE_NAME + 
       " values("
       +"\"" + map.get(DBColumns._ID) +"\","
       +"\"" + map.get(DBColumns.NAME) +"\","
       +"\"" + map.get(DBColumns.TEL) +"\","
       +"\"" + map.get(DBColumns.EMAIL) +"\""
       + ");";

     getWritableDatabase().execSQL(sql);
 }

 @Override
 public void deleteData(Object obj) {
  // TODO Auto-generated method stub
  HashMap<String, String> map = (HashMap<String, String>)obj;
  String sql = String.format("DELETE FROM "+ TABLE_NAME+" WHERE _id = '%s' ", map.get(DBColumns._ID));
  getWritableDatabase().execSQL(sql);
 }


 @Override
 public void updateData(Object obj) {
  HashMap<String, String> map = (HashMap<String, String>)obj;
     ContentValues values = new ContentValues();
     
     String sql = "UPDATE "+ TABLE_NAME + 
       " SET "+DBColumns.NAME+" = ?, "
       +DBColumns.TEL+" = ?, "
       +DBColumns.EMAIL+" = ? "+
       "WHERE _ID = ? ";
     Object[] bindArgs = new Object[]{map.get(DBColumns.NAME),map.get(DBColumns.TEL),map.get(DBColumns.EMAIL),map.get(DBColumns._ID)};
     getWritableDatabase().execSQL(sql,bindArgs);
 }


 @Override
 public void FindAllData() { 
   String query = "SELECT * FROM "+TABLE_NAME;
   Cursor cursor = getWritableDatabase().rawQuery(query, null);
    
    
    StringBuffer sf = new StringBuffer();
    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
     sf.append(cursor.getInt(0)).append(" : ")
     .append(cursor.getString(1)).append(" : ")
     .append(cursor.getString(2)).append(" : ")
     .append(cursor.getString(3)).append("\n");
     cursor.moveToNext();
     }
    Log.d("Ted", sf.toString());
 }


 @Override
 public void FindLastID() {
  Cursor cur = getWritableDatabase().rawQuery("select LAST_INSERT_ROWID() ",null);
        cur.moveToFirst();
        Log.d("Ted","LAST ID"+ String.valueOf(cur.getLong(0)));
 }

}

上面實作了簡單的 insert ,update, del ,FindLastId , FindAllData的方法
當然其實也可以簡單的使用getWritableDatabase().insert getWritableDatabase().update getWritableDatabase().del  只是作者想順便練練execSQL的寫法而已 XD


若有興趣看看sampleCode 可以使用下面的網址

Sample Code

2013年12月11日 星期三

OOAD原則 (六) Ioc Inversion of Control (DIP依賴倒置原則 - 續)

DIP 是個理論,而如何達到這個目標就必須使用IoC這個技巧,

IoC容器

  • 會實踐Dependency injection
  • 提供設定dependency的方法
講白話點就是
  • 創造dependency /object 
  • 注射或傳遞dependency



接著我們來看一下範例

根據  DIP 依賴倒置原則 這篇文章,我們可以將該範例的UML畫出來如下圖



class EatRiceBehavior 
{
 void eat()
 {
  System.out.println("Person_EATRice");
 }
}
public class Person
{
 EatRiceBehavior behavior=new EatRiceBehavior();
 public void eat() {
  // TODO Auto-generated method stub
   behavior.eat();
 }
 public static void main(String[] args) 
 {
  Person person = new Person();
  person.eat();
 }
 
}

人吃飯,人擁有吃飯的物件來實做吃飯該做的事情,但是依賴於具象是不好的,會造成程式的高耦合性,應該依賴於抽象,所以我們更改架構變成下圖


interface Behavior
{
 void eat();
}
class EatRiceBehavior implements Behavior
{

 @Override
 public void eat() {
  // TODO Auto-generated method stub
  System.out.println("eat rice");
 }

}
class EatNoodleBehavior implements Behavior
{

 @Override
 public void eat() {
  // TODO Auto-generated method stub
  System.out.println("eat  EatNoodle");
 }
}
class EatDumplingBehavior implements Behavior
{

 @Override
 public void eat() {
  // TODO Auto-generated method stub
  System.out.println("eat  Dumpling");
 }
}

public class Person
{
 Behavior behavior;
 public void eat(Behavior behavior) {
  behavior.eat();
 }
 public static void main(String[] args) 
 {
  Person person = new Person();
  person.eat(new EatRiceBehavior ());

 }
 
}


我就沒有畫出noodle 還有 dumpling的class了 ,但是他的意義其實是,



用程式的意義來說明

原本Person 依賴於 EatRiceBehavior ,當人想要eat的時候就會將指令傳達給EatRiceBehavior
當要吃麵的時候就會將指令傳達給EatNoodleBehavior 這樣的缺點是當想吃其他的東西時參數並無法共用,會產生出許多參數造成管理不便,
但是經過我們修改之後我們將控制權交給了interface Behavior
使得 EatNoodleBehavior、 EatDumplingBehavior、 EatRiceBehavior 皆依賴於Behavior
,只要有人擁有Behavior就擁有他們的控制權,然而Person恰巧擁有Behavior,這使得Person能夠輕易的控制那三個Behavior。



用注射傳遞的方式來說明

我們將Behavior 注射/傳遞至Person內  Person就是Ioc容器他會負責幫我們在class之間做溝通
讓我們可以在上層與下層之間做溝通而不依賴於彼此

OOAD原則 (五) DIP 依賴倒置原則

Dependency Inversion Principle 依賴倒置原則主要有個要點
  • 依賴抽象類別,不要依賴具象類別。



簡單的說就是class 之間用interface/abstract 來溝通
下面是個簡單的人吃飯的例子。

class EatRiceBehavior 
{
 void eat()
 {
  System.out.println("Person_EATRice");
 }
}
public class Person
{
 EatRiceBehavior behavior=new EatRiceBehavior();
 public void eat() {
  // TODO Auto-generated method stub
   behavior.eat();
 }
 public static void main(String[] args) 
 {
  Person person = new Person();
  person.eat();
 }
 
}


但是當我想新增人吃麵的行為,原本的程式就不能使用了,因為他依賴於具象類別(EatRiceBehavior ),所以我就必須在class 裡面增加 EatNoodle Nbehavior; 類似這樣的參數,接著當我新增了越來越多的物件時這段程式就會變成類似下面這樣


public class Person
{
 EatBehavior behavior;
        EatNoodle  Nbehavior;
              Eatdumpling Dbehavior;  
public void eat(string val) { // TODO Auto-generated method stub if(val.equals("rice")) behavior.eat();
                else if(val.equals("noodle")) Nbehavior.eat();
                else Dbehavior.eat();
 }
 public static void main(String[] args) 
 {
  Person person = new Person();
  person.eat("rice");
 }
 
}


這樣的程式是非常可怕的,難以維護且重複性極高,
這時候還好有Dependency Inversion Principle,他告訴我們依賴於抽象而不依賴於具體類別
所以我們就可以寫出下面的例子


interface Behavior
{
 void eat();
}
class EatRiceBehavior implements Behavior
{

 @Override
 public void eat() {
  // TODO Auto-generated method stub
  System.out.println("eat rice");
 }

}
class EatNoodleBehavior implements Behavior
{

 @Override
 public void eat() {
  // TODO Auto-generated method stub
  System.out.println("eat  EatNoodle");
 }
}
class EatDumplingBehavior implements Behavior
{

 @Override
 public void eat() {
  // TODO Auto-generated method stub
  System.out.println("eat  Dumpling");
 }
}

public class Person
{
 Behavior behavior;
 public void eat(Behavior behavior) {
  behavior.eat();
 }
 public static void main(String[] args) 
 {
  Person person = new Person();
  person.eat(new EatRiceBehavior());
 }
 
}


現在不管新增了甚麼行為進來,都不至於造成太大的影響。

2013年12月3日 星期二

OOAD原則 (四) 委派 vs 合成 vs 聚合

委派

將特定工作的責任委派給一個類別或方法
譬如下面的例子:
老闆說要蓋大樓,接著當然不會是老闆蓋大樓,
老闆會將這個工作委託給工人們,由工人們就去蓋大樓。



class Worker
{
 public void Work()
 {
  System.out.println("Do Work");
 }
}

class Boss
{
 private Worker labor = new Wroker();
 public void Build()
 {
  labor.Work();
 }
}
public class delegate {

 /**
  * @param args
  */

 public static void main(String[] args) {
  // TODO Auto-generated method stub
  Boss boss = new Boss(); 
  boss.Build();  
 }

}


合成

擁有一組其他類別的行為,
還有一個重點是當合成的物件消失他所擁有的其他類別的行為也會消失。
下面的例子:
ArmsDealer擁有Weapon,
當ArmsDealer 被殺掉的話使用者就無法取得購買Weapon的通路。


interface Weapon
{
 public void Attack();
}
class Sword implements Weapon
{ 
 public void Attack()
 {
  System.out.println("Sword Attack");
 }
}
class Bow implements Weapon
{
 public void Attack()
 {
  System.out.println("Bow Attack");
 }
}
class ArmsDealer
{
 ArrayList<Weapon> list = new ArrayList<Weapon> ();
 public ArmsDealer()
 {
  list.add(new Bow());
  list.add(new Sword());
 }
 public Weapon GetWeapon(int index)
 {
  return list.get(index);
 }
}
public class Game {

 
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  ArmsDealer dealer= new ChooseWeapon();
  dealer.GetWeapon(0).Attack();
 }

}

聚合

跟合成最明顯的差異就是,當聚合物件被摧毀時,他所擁有的物件並不會跟著一起銷毀。
下面的例子:
Ted是個司機當車子報廢的時候Ted還是可以去開motoBike並不會因為車子報廢Ted就跟著一起消失...如果這樣也太可怕了XD

abstract class Driver
{
 abstract public void Drive();
}
class Ted extends Driver
{
 public void Drive()
 {
  System.out.println(" Driving");
 }
}

class Car
{
 private Driver driver;
 public Car(Driver ted)
 {
  this.driver= ted;
 }
 public void Move()
 {
  driver.Drive();
 }
}

class MotoBike
{
 private Driver driver;
 public MotoBike(Driver ted)
 {
  this.driver= ted;
 }
 public void Move()
 {
  driver.Drive();
 }
}
public class Aggregation {

 /**
  * @param args
  */
 public static void main(String[] args) {
  Ted ted = new Ted();
  Car car = new Car(ted);
  car.Move();

 }

}


結論

委派是將某個行為委託給別人去做
ex:老闆叫員工去寫code

合成是擁有其他類別的資訊且當該類別被destroy的時候他所擁有的資訊也會一併消失
ex:冰淇淋被吃掉,上面的配料也都一併進到肚子裡去(消失)。

聚合也是擁有其他類別的資訊但是當該類別被destroy的時候他所擁有的資訊並不會一併消失
ex:司機開車,假設車子報廢,司機還是可以開新車。

2013年12月2日 星期一

Eclipse Theme

這是一個可以改變Eclipse主題的套件,如下圖所示


使用步驟如下


首先
進入Help -> Install New Software 安裝該軟體






在name可以隨便Key
在網址處key 入 http://eclipse-color-theme.github.io/update/
接著next 按到底就完成了


接著
到 http://eclipsecolorthemes.org/ 選擇喜歡的主題 點擊進去之後





接著點選Download底下的 (EPF) Eclipse Preference
下載下來之後將檔案import進去  點選Preferences




將剛剛下載的檔案Import進來





接著新的主題就出現了



2013年11月25日 星期一

Git (二) Rebase vs Merge

rebase 跟 merge 做的事情其實很像

主要的差別在於
假設我在 branch下指令  git merge master,
merge 會一次性的將所有master的commit 直接merge進 branch
rebase的話  則會分成多次commit 進來




舉個例子來看看


上面分別有master and branch 兩個分支
我在 branch 上做了兩次commit  branchC  and branchD
然後我在 master 上做了三次commit masterA ,masterB and masterC



Merge

首先我們先使用merge 指令
在branch分支下指令 git merge master
master的資料將會在一次commit 中將 masterA , masterB and masterC
都加進我的branch分支內,我們看到的commit結果會是如上圖
branchC, branchD ,Merge branch 'master' into branch ,
要倒回去的話只需要下指令git reset --hard HEAD^
就可以恢復merge之前的狀態



Rebase 

接著使用 rebase 指令
在branch分支下指令 git rebase master



可以看到原本分為兩個的分支結合再一起了
可以看到git rebase master之後的結果會是  
masterA , masterB, masterC , branchC and branchD 跟git merge master的結果有些差別
不過上圖並不好解釋會何會變成這樣,下面的圖比較能解釋他的原因

原本的基準點為左圖最下的藍色點,
當我們使用 git rebase master時,branch分支會將基準點從最下方的藍色點rebase到 master 的最上方的點,也就是如右圖所示(可以把他想成pointer 將指標指過去的感覺),
所以最後會只看到一條線。
經過rebase之後的分支要倒回並不是那麼的容易,
我的做法會是在create一個新的分支,然後將這次的Rebase都倒回之後再用cherry-pick將原本的commit 拉回來。



結論

            git merge master是一次性的commit ,然而git rebase master是多次性的commit 。


git merge 的commit是依照順序的 branchC, branchD 然後將master commit 進來masterA masterB masterC,
所以結果會是:branchC, branchD masterA masterB masterC
然而git rebase 的commit是先rebase到master分支再將原本的commit apply回來
所以順序會是: masterA masterB masterC branchC, branchD


Merge和Rebase的用途也不太相同

通常Rebase的用途在於  有同事在遠端commit了新的code進來
我希望我現在修改的版本能base到最新的版本
這時候就可以使用rebase command 讓手邊的程式更新到最新的版本

Merge的話比較像是我在某個分支完成了一個大型修正或功能,而且也經過大量測試之後
想要將這個功能導入我現在的working directory,
這時候就可以使用merge, 記住 merge是一次性的commit 所以所有關於該feature的功能將會一次性的導入你並不會在working directory中看到有關於該feature的其他commit




2013年11月24日 星期日

Git (一) git reset

今天要談的是git  reset的功能, git reset有分三個選項

git reset --soft
git reset --mixed 也就是 git reset
git reset --hard

首先我們要分成三個部分說明






當我們新增了一個 hello.txt 檔 到 working directory之後,
我們希望將該file commit 進  git directory,
首先我們必須下指令 git add hello.txt , 將我們希望更改的檔案放進 staging area,
接著再下指令  git commit -m "add hello"     ("add hello" 為 commit的文字描述),
然後資料就會進到git directory了。
                     
                                            太好了所有的修改都加進了git directory 我可以收工了。

可惜....  事與願違,當初做 add hello 這個修改時,我除了修改了這個檔案 hello.txt之外,我還修改了world.txt這個檔案。
     
                            糟了,我commit出了差錯老闆知道的話一定會把我臭罵一頓。

還好git 有支援倒回的指令,
我們只需要下指令 git reset --soft HEAD^ 就會將這次的commit 取消,
然後我們只需要再下  git add world.txt -> git commit -m "add hello"  ,這樣就神不知鬼不覺的將資料加進這次commit了。

當然我們也可以下指令 git reset --HEAD^ ,直接取消掉 commit 以及 staging area , 回到 working directory ,這個階段所有的資料都尚未被加入 staging area,
然後接著下指令 git add hello.txt -> git add world.txt -> git commit -m "add hello"
就好了。

然後值得注意的是 git reset HEAD^git reset --hard HEAD^ 的差別在於
git reset --hard HEAD^ 會將該次的修改也一併倒回,也就是當我下了這個指令之後
hello.txt and world.txt將回到上一次commit 的版本 (這次所做的所有修改也都會消失)

                            除非你知道正在做甚麼,
                                 否則不要輕易下這個指令,不然辛苦修改的成果可能就在瞬間被銷毀。

git reset 也可以用於 fast forward 只需要知道想要fast forward的SHA
使用 git reset --hard xxxxxx        xxxxxx 為 head的SHA
這樣就會使分支跳到指定的位置