2012年9月15日

軟體設計樣式#Prototype

Prototype Pattern
雛形樣板(Prototype Pattern)是一種自我複製的架構,將原型的物件自我複製來生成一個全新的物件,在遊戲程式設計,已經廣泛的使用。複製最有名的方法可以分為淺度複製(Shallow copy)和深度複製(Deep copy)。

(1)淺度複製 : 當複製的對象為值型別(value type)就直接複製其值; 如果複製對象是參考值(reference value )只會複製它的參考值,不會複製內容。
(2)深層複製 : 不管對象是值型別(value type)還是參考值(reference value )它都會完整複製其內容。

(3)管理的層面: 當我們複製新的物件時,如何去管理這些物件。

架構圖:


例子:
         我們製作一款遊戲,當主角遇到妖怪時,妖怪會使用兩種分身術來迎戰,第一種分身為淺分身術,當其中有一個妖怪死完就過關。第二種分身為深度分身術,需要將所有的妖怪殺死才會過關。利用prototype來設計妖怪的分身術的方法。

第一種:淺分身術



Monster描述
   
public class Monster implements Cloneable{

// Data field
private String name ; //名稱
private MonsterBlood blood ; //血量

    public Monster(String name  )
    {
    this.name = name ;
    this.blood = new MonsterBlood(10000);
    }

// Sallow Copy Method
public Object clone()
{

try {
System.out.println("妖怪 使用分身術");
  return super.clone() ;
   } catch (Exception e) {
   return  null ;
   }
}

//被攻擊
public void hurtSelf(Integer blood)
{
this.blood.setBlood(this.blood.getBlood()-blood) ;
}

public String toString()
{
String str = " Name:"+name+" ,blood:"+this.blood.getBlood() ;
return str ;
}

}

   

TestMonster 測試
   
public class TestMonster {

public static void main(String[] args) {

System.out.println("主角遇到妖怪 !!");

//妖怪宣告
Monster monster1 = new Monster("水怪") ;
Monster monster2 = (Monster)monster1.clone() ;

System.out.println("Monster_1:" + monster1.toString());
System.out.println("Monster_2:" + monster2.toString());

System.out.println("主角使用絕招 !!");
monster1.hurtSelf(10000);

System.out.println("Monster_1:" + monster1.toString());
System.out.println("Monster_2:" + monster2.toString());
}


   



第二種:深分身術

它會實際物件完全產生一個新的實體,當參照改變時,複製的實體並不會被改變內容。

Monster2描述
    
public class Monster2 implements Cloneable{

// Data field
private String name ; //名稱
private MonsterBlood blood ; //血量

    public Monster2(String name  )
    {
     this.name = name ;
     this.blood = new MonsterBlood(10000);
    }

// Sallow Copy Method
public Object clone()
{
try { System.out.println("妖怪 使用分身術"); Monster2 monster = new Monster2(name) ; return monster ; } catch (Exception e) { return null ; }
}

//被攻擊
public void hurtSelf(Integer blood)
{
 this.blood.setBlood(this.blood.getBlood()-blood) ;
}

public String toString()
{
String str = " Name:"+name+" ,blood:"+this.blood.getBlood() ;
return str ;
}

}

   


TestMonster 測試
    
public class TestMonster {

public static void main(String[] args) {

System.out.println("主角遇到妖怪 !!");

//妖怪宣告
Monster monster1 = new Monster("水怪") ;
Monster monster2 = (Monster)monster1.clone() ;

System.out.println("Monster_1:" + monster1.toString());
System.out.println("Monster_2:" + monster2.toString());

System.out.println("主角使用絕招 !!");
monster1.hurtSelf(10000);

System.out.println("Monster_1:" + monster1.toString());
System.out.println("Monster_2:" + monster2.toString());
}
























軟體設計樣式#Singleton

Singleton Method

singleton為獨一無二的意思,代表它是國士無雙的一個實例,主要考量資源有限的情況下,希望實例建立時只建立一次,之後其他程式都只會相同一個實例的方法,並不會因為其他程式再次宣告此實例而去多建立多個實例。例如: 資料庫的connection是有限的情況下,只希望同一條去進行資料處理、或是實例不想要多人使用的情況下。

架構圖:

例子:
建立一個計數器(counter),只要有建立新的實例就會加一並且給一個編號(id),下列是它的類別圖。



例子:
Counter.java
 Counter物件
   
public class Counter {

// data field 
private static Counter counter =null ;
private static int countNumber=0;
private static int id =0 ;

//constructor
private Counter(){} ;

//get only one instance
public static Counter getInstance(){

if(counter==null)   // 只會建立一次
{
  counter =  new Counter()  ;
  id = (int)(Math.random()*1000); //產生id
  countNumber++;

}

return counter ;
}

//return  count number
public int getCountNumber()
{
return countNumber ;
}

//return id
public int getId()
{
return id;
}
}



   
說明:  使用singleton的要訣,一開始需要把建構子宣告為private,讓它不能new實例。利用static來宣告,讓她只可以宣告一次。


TestCounter.java
測試Counter程式
   
public class TestCounter {

public static void main(String[] args) {

Counter counter1 = Counter.getInstance() ;
System.out.println("counter1 ID:"+counter1.getId());
System.out.println("counter1 CounterNumber:"+counter1.getCountNumber());

Counter counter2 = Counter.getInstance() ;
System.out.println("counter2 ID:"+counter2.getId());
System.out.println("counter2 CounterNumber:"+counter2.getCountNumber());
}
}


   
結果:

counter1 ID:66
counter1 CounterNumber:1
counter2 ID:66
counter2 CounterNumber:1


















2012年9月14日

軟體設計樣式#Factory

Factory Method
工廠模式(factory pattern)主要是用在當工廠要生產產品時,有不同的產品但是卻有類似的行為與屬性,例如:今天是生產罐頭的工廠,有各式各樣的罐頭要生產,但是他們加工的方法有所不同,像水果、飲料或是畜牧都不一樣。所以工廠模是常用在相同方法宣告,但是有不同的實做方式。在實作工廠方法之前,需要考慮幾點特性: 1.它具有封裝方法且需實作必要性 ,  2.工廠模式可以挑選適合的加工方式 。 


架構圖:



例子:

今天我們實作一個日誌器(logger),主要呈現工廠如何去分配不同的實作方法,好處1.可以集中管理實例 2.可以利用外部文件去控制文件。以下是我們的UML類別圖,首先為定義產品規格書(logger)的方法規格,再去實作FileLogger和ConsoelLongger實例。利用LoggerFactory來產生多種logger的產品。


      Logger.java

Logger方法介面描述
    public interface Logger{
 
    // method spec
    public void log(String msg) ;
 }

FileLogger.java

   

FileLogger實例
   
public class FileLogger implements Logger{

@Override
public void log(String msg) {

File file = null ;
FileWriter write = null ;
try {

file = new File("D:\\log.txt") ;
write = new FileWriter(file);
write.write(msg);

} catch (Exception e) {

}finally{
try {
write.close() ;
} catch (Exception e2) {}
}

}

   
ConsoleLogger實例
   
public class ConsoleLogger implements Logger{

@Override
public void log(String msg) {
System.out.println(msg);
}


   

 
LoggerFactory實例
   

public class LoggerFactory {

   public boolean isFileLoggingEnabled()
   {
           //取得外部設定檔文件
  Properties p = new Properties();

  try {
  File file = new File("Logger.properties");
   p.load(ClassLoader.getSystemResourceAsStream
                   (file.getName()));
  String islogfile = p.getProperty("FileLogging");
  System.out.println("islogfile:"+islogfile);

  if(islogfile.equalsIgnoreCase("on"))
    return true;
  else
  return false ;
} catch (Exception e) {
e.printStackTrace();
return false ;
}
   }
 
 //assign instance method
   public Logger getLogger()
   {
  if(isFileLoggingEnabled())
  {
  return new FileLogger();
  }else{
  return new ConsoleLogger();
  }
   }
}


Logger.properties 文件設定檔
   
FileLogging=on

   



TestLogger實例
   

public class TestLogger{

public static void main(String[] args) {

LoggerFactory factory = new LoggerFactory() ;
Logger log = factory.getLogger() ;
log.log("AAAA") ; 

}
}