2016年1月20日 星期三

使用nvm 做 node.js 版本管理教學

像node.js這種版本更迭快速的引擎,
為了要測試程式在不同版本的結果,
常常要安裝很多個版本,
於是就有了node version manager這類的工具。

根據作者github,目前不支援homebrew installation,
要用github 上的安裝指令來裝。

這是目前的安裝指令:
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.1/install.sh | bash
目前預設的安裝位置是/user/local/opt/nvm/
安裝程式會自動把source加到profile裡(~/.bash_profile, ~/.zshrc or ~/.profile)。
加入這行:
source /usr/local/opt/nvm/nvm.sh
你也可以指定要安裝的source,directory,profile,(github上的說明有寫)
之後,就可安裝你需要的node版本:

安裝5.0最新版本:
$nvm install 5
or
$nvm install v5
或指定明確版本:
$nvm install v5.10
版本編號可以用這些取代:
node:安裝node最新版
iojs:安裝io.js最新版

安裝最新版本,並且搬移之前的npm版本:
$nvm install node --reinstall-packages-from=node
安裝指定版本,並且搬移之前npm的指定版本:
$nvm install v5.0 --reinstall-packages-from=4.2
shell中使用指定版本:
$nvm use 5.0
直接執行:
$nvm run 5.0

2016年1月14日 星期四

來個標註吧 - Java annotation

Annotation在java裡,是給編譯器看的,
作用是告訴編譯器去做什麼,或是不做什麼。

Annotation package:
import java.lang.annotation.*;
先來看看它的語法,通常長的像這樣:
@annotation
或是這樣:
@annotation(value)
@annotation(element=value)
Annotation可指定element的值,或是直接傳入值。
它可以針對java的任何元素,
例如package、class、function、member...等進行標註。
像是這樣子:
class smaple{
    @Override
    public function overrideFunc(){
    }
}
那麼Annotation到底有什麼用,
我們來看看內建的幾個annotation。

@Override

告訴編譯器這個方法要覆蓋父類的方法,
例如上面的例子就是。
使用Override可以確保程式一定會覆蓋,
而不是變成重載。

@SuppressWarnings

這是告訴編譯器不要發出警告。
下面這個程式碼,編譯器會發出falling through warning。
switch("b"){
    case "a": break;
    case "b": //falling through
    case "c": break;
}
如果加上@SuperssWarnings annotation就不會發出警告。
@SuppressWarnings
private fallingThroughFunc(char x){
    switch(x){
        case "a": break;
        case "b": //falling through
        case "c": break;
    }
}
常用的參數有這些:
all
finally
unchecked
serial
fallthrough
path
你可以在命令列下這個指令,查到全部的參數
javac -X

@Deprecated

這個是純粹用來說明的,
告知開發者這個元素不建議使用,
請使用新的元素。
@Deprecated
public void deprecatedFunc(){
}

meta annotation

meta annotation是註釋的註釋,
annotation for annotation,好繞口啊。

@Retention

它告訴編譯器這個annotation的存在時期。
下方的例子,是告訴編譯器Deprecated一直到runtime都存在,
表示程式執行期同樣可以存取到。
@Retention(value=RUNTIME)
@Deprecated

Retention的參數有這些:
import java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.RetentionPolicy.SOURCE;
import java.lang.annotation.RetentionPolicy.CLASS;

@Inherited

使用Inherited來註釋一個class,
那麼它的子class也會繼承這個註釋。

@Documented

製作javadoc時,
使用Documented註釋某個annotation,
那麼這個被註釋的annotation會包含在javadoc中。

@Target

Target指明這個annotation可用在哪些元素。
import java.lang.annotation.ElementType.*;

@Target(ElementType.METHOD)
public @interface TargetSample{}
表示TargetSample只能用在mehtod。
@Target可以有多個值,像是這樣。
import java.lang.annotation.ElementType.*;

@Target(value={ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
public @interface TargetSample{}

2016年1月11日 星期一

軟體架構做什麼用?

軟體架構在軟體工程上究竟能帶來什麼好處?
一般來說,只要提到『架構』兩個字,
地位好像就很崇高,給人一種無法親近的fu,
軟體架構也是如此,
所以我們常常會看到開發人員討論某個問題怎麼解?
但是很少聽到大家研究架構怎麼做。

舉凡要讓人接受一項新東西,
不外是威脅或利誘兩種方式。
專案開發一向講求「以和為貴」,
我們當然不能用威脅的,
而是要告訴大家服用後好處多多,
保證一日雙北,或是30分鐘登上101。

好的架構能讓開發更快速

架構定了,開發人員有完成目標,有規範可遵守,
有方式可合作,整體開發能夠更順利。
且好架構是適應變化的,
面對未來的改變,也能有一定的彈性。

架構明確出團隊的共同目標

有目標,方向才不會亂。
團隊有共同的目標,才不會互相掣肘,
從而發揮1+1>=2的效果。

架構具體化團隊使用的技術

團隊中的成員未必都熟悉系統所使用的技術,
確定出技術後,成員可以提前練習,
也方便互相研究。

架構勾勒出每個人的責任

多人共同開發要順暢有一個重點,
就是每個人清楚知道自己的責任範圍。
責任範圍一確認,就能避免重疊和遺漏的部分,
團隊協力完成預先規劃的全部內容。

2016年1月9日 星期六

2016年1月7日 星期四

Class serialization between smartfox and unity / smartfox 類別序列化教學

Smartfox 要使用class serialization,有幾個項目要做。

1 server/client雙邊都要有這個class,且package相同。
2 java class要實作com.smartfoxserver.v2.protocol.serialization.SerializableSFSType。
3 java class單獨編譯成jar,放到extensions\__lib__\。
4 unity c# class要實作Sfs2X.Protocol.Serialization。
5 unity c#要using Sfs2X.Protocol.Serialization
及System.Reflection
且呼叫 DefaultSFSDataSerializer.RunningAssembly = Assembly.GetExecutingAssembly();

現在來看看它的用法。

Server Side

首先我們定義一個要序列化的類別,
這個類別要實作SerializableSFSType。
Class編譯成jar,放到extensions\__lib__\。

package com.sample.model;

import com.smartfoxserver.v2.protocol.serialization.SerializableSFSType;

public class SampleClass implements SerializableSFSType {

    public String id="id_from_server";
    public int hitPoints=10;
    public int count = 10;
     
    public SampleClass()
    {
 
    }
}

把這個類別傳給client端的時候,使用class類型。

SampleClass sc=new SampleClass();
ISFSObject resObj=SFSObject.newInstance();
resObj.putClass("sc", sc);
send("cmd",resObj, user);

Client Side

Client也需要一個相同的class,
client的class package需和java class相同。
client class要實作Serialization。

using Sfs2X.Protocol.Serialization;
using com.smartfoxserver.v2.protocol.serialization.SerializableSFSType;
namespace example{
    public class SampleClass : SerializableSFSType {

        public string id="cid";
        public int hitPoints=0;
        public int count = 0;
    }
}

Client接收server傳來的class時需要呼叫DefaultSFSDataSerializer,

DefaultSFSDataSerializer.RunningAssembly = Assembly.GetExecutingAssembly();
這行通常可放在new SmartfoxServer之後,
要確保SFSDataSerializer可見到需要處理的class。

using Sfs2X.Protocol.Serialization;
using System.Reflection;
DefaultSFSDataSerializer.RunningAssembly = Assembly.GetExecutingAssembly();
//other code....
private  void OnExtensionResponse (BaseEvent evt)
{
    ISFSObject obj = (SFSObject)evt.Params ["params"];
    SampleClass sc=(SampleClass)obj.GetClass("sc");
    String id=sc.id;   //get field
}

2016年1月5日 星期二

java的反射機制 Reflection API

Reflection簡單的說,當你在寫code的時候,
有時你並不知道要實體化哪一個class,
而是在執行階段才決定實體化哪個class,
這時候就可以使用Reflection API。

使用反射實體化class

方法一:
取得class,然後實體化它。
這時使用的是預設建構式。

Class<?> clazz=Class.forName(className);
Fo fo=(Fo)clazz.newInstance();

方法二:
如果class 沒有default constructor
或是有數個constructor,
而你想指定使用其中一個。

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

Class<?> clazz=Class.forName(className);
//使用參數型態為String的constructor
Constructor<?> constructor=clazz.getConstructor(String.class);
//實體化
Object obj=constructor.newInstance("hi");


操作class的Method
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;

//取得class
Class clazz=Class.forName("someClass");

//取得method,並且指定參數類型
Method method=clazz.getMethod("methodName",String.class,int.class);

//取方法的修飾詞
int modifier=method.getModifier();

//取方法返回值
Type type=method.getGenericReturnType();

//取方法參數類型
Class[] klasses=method.getparameterTypes();

//取得method
Method med=clazz.getMethod("getInstance",int.class);

//呼叫static method,得到回傳值
Object resObj=med.invoke(null);

//取得method
Method noStaticMethod=clazz.getMethod("noStaticMethod",int.class);

//呼叫method,傳入呼叫這個方法的物件及參數,得到回傳值
Object resObj=noStaticMethod.invoke(clazz.newInstance(),3);