其他特殊類別

      在〈其他特殊類別〉中尚無留言

列舉(Enumerations)

列舉用來定義新型的資料型別, 實際上就是一種類別, 可單獨撰寫, 也可以當成內部類別

enum PowerState{
    OFF,
    ON,
    SUSUPEND;
}

使用方式

comp.setState(PowerState.OFF); <==直接用OFF, 不是轉成數字
private PowerState powerState=ON;

public void setState(PowerState state){
    switch(state){
      case OFF:...
     }
}

複雜的列舉

列舉可以有欄位, 方法及private 建構子

enum PowerState{
     OFF("The power is off"), //呼叫建構子, 初始化public static OFF 參考
     ON("The power is on"),
     SUSUPEND("The power usage is low");
     private String description;
     private PowerState(String d){
          description=d;
     }
     public String getDescription(){
          return description;
     }
}
public class Test{
     public static void main(String[] args) {
          System.out.println(PowerState.OFF);
          PowerState s=PowerState.ON;
          System.out.println(s.getDescription());
     }
}

列舉的建構子只能是private or 預設, 因為列舉不能new 出新物件

enum只有當成內部類別才可以加上static, 不過編譯器會自動幫內部類別加上static final.
若是當成外部類別, 而且有加上public的話, 則檔名一樣要跟enum類別名相同

enum Week{Sunday, Monday, Tuesday, Wednesday, Thrusday, Friday, Saturday};
若為外部類別, 則會編譯出Week.class, 若是內部類別, 則會編譯成Test$Week.class. 列舉的class 都是final的, 裏面的值全都是public static final, 如下
public static final Week Sunday;
public static final Week Monday;

取得單一值
Week week=Week.Sunday

取得全部的值
Week[] week=Week.values(); 則week陣列就會取得從Sunday到Saturday等7個值

使用valueOf(String)
Week week=Week.valueOf(“Sunday”);

設計模式(Design Pattern)

設計模式是依前人的經驗針對某種問題的解決方案, 且可應用於不同的系統中, 使得設計出來的程式更具彈性. Design Paterns: Elements of Resuable Object-Oriented Software這本書記載著24種設計模式

單例模式(Singleton pattern)

只能產生出一個物件, 並提供一個方法讓其他程序可以隨時調用並取得該物件. 主要是解決物件共用資源共享的問題, 比如一個專門配置全域訊息的服務或是Factory資源等.

class Singleton{ 
     private static Singleton object=null; 
     private Singleton(){} 
     public static Singleton getInstence(){ 
          if (object==null){ 
              object=new Singleton(); 
          } 
          return object; 
     }
 }

需使用private static  Singleton object指向此物件
需使用private 建構子, 禁止由外部產生此物件
需使用public static Singleton getInstance()判繼物件是否生成, 若為null, 才產生物件
如果object 是null, 則需直接生成物件 : object=new Singleton();

DAO設計模式

Data Access Object, 資料數據存取介面, 介於商業邏輯層及數據資料層之間, 又來降低這二層的耦合(coupling[ˋkʌplɪŋ])
商業邏輯層 : 就是使用者開發的app
數據資料層 : 就是資料庫
耦合coupling : 依賴, 連結
內聚Cohesion[koˋhiʒən] :將一致性的工作集合在一起

DAO的優點如下:
降低這二層的相依性
將資料存取封在DAO裏, 可集中管理, 也可降低應用程式開發的困難度
若要變更資料庫來原(如由MySQL變更為MSSQL), 不會影響商業邏輯層

未脫勾的寫法

class Customer{
    private int id;
    private String name;
    private Date birthday;

    //商業邏輯層的方法
    public int getId(){}
    public String getName(){}
    public Date getBirthday(){}

    //Persistence 持久性方法
    public void add(Customer cust){}
    public void delete(int id){}
    public Customer findById(int id){}
    public void update(Customer cust){}
}

持久性方法(Persistence) : 對資料庫或硬体作操作及查詢的程序

上述的新增, 修改, 刪除, 查詢, 須從邏輯層中脫勾

脫勾後的設計模式
VO(Value Object) : 資料記錄單元, 如上面的Customer, 也就是商業邏輯層
DatabaseConnection : 資料庫連線
DAO 介面 : 規範對資料庫操作的持久性方法
DAOImpl : 實作DAO介面, 但不包含資料庫打開及關閉
DAOProxy : 就是DAOImpl 加上開啟關閉資料庫
DAOFactory : 取得DAO物件

由Factory取得DAO常見的方法
CustomerDAOFactory factory=new CustomerDAOFactor();
ICustomerDAO dao=factory.createCustomerDAO();

Composition Pattern

討論程式碼共時, 最常用的就是繼承. 但在組合模式上, 有另一種思維.

組合的重點就是在整合多種且複雜的物件, 透過委託方法(Method delegation)設計手段來達成.

說的更直白一點, 組合就像現在台灣的系統整合廠(ODM), 將各個廠商所提供的零件(面板, 電池, SOC)整合成一支手機, 他們不管面板怎麼作出來的, 也不管SOC的技術, 反正就是組合就對了

再比如台灣的汽車廠(中華), 向外購買輪胎, 板金, 及日本的引擎, 然後組合成一台車子. 所以台灣現在連引擎都作不出來, 因為都是委託別人作的

現實生活中, 這些廠商持續敗壞台灣的經濟, 也讓台灣失去了競爭力. 但寫程式時, 為了加速開發速度, 也採用這模式, 甚至連程式都委外別人寫

組合物件通常有 “has a” 的關係. 真實世界中, 輪子, 方向盤, 變速箱, 引擎等獨立物件並沒有任何功能. 但車子組合了這些物件而產生了功用.

撰寫視窗程式時, 不用自己寫button, label , ImageView, 直接由別人寫好的label物件拉進來即可. 所以我們的視窗 has a Lable

巢狀類別

巢狀類別(Nested Class)又稱為內部類別, 是被宣告在另一個類別之內, 有內部類別及static 巢狀類別二種.
內部類別又有成員類別(Member class), 區域類別(Local class), 及匿名類別(Anonymous class)三種

為什麼要使用巢狀類別? 如果此類別僅使用在某一類別之中, 則可使用巢狀類別. 將內部類別隱藏在外部類別之內, 此時可存取外部類別的private 方法及變數, 以方便維護

static 巢狀類別不屬於內部類別, 但宣告的位置同成員類別, 只是前面加了static. 可以於外部類別實例化, 並禁止使用外部類別的非static 成員變數

成員類別

又稱一般內部類別, 宣告在field之處

    class MyOuter{
        private static int ss=9;
        private int x=7;
        class MyInner{
            int x=77;
            public void foo(){
                int x=777;
                System.out.println("Local x="+x);
                System.out.println("MyInner x="+this.x);
                System.out.println("MyOuter x="+MyOuter.this.x);
                System.out.println("MyOuter ss="+MyOuter.ss);
            }
        }
    }
    public class NestedClassTest {
        public static void main(String[] args) {
            MyOuter outer=new MyOuter();
            MyOuter.MyInner inner=outer.new MyInner();
            inner.foo();
        }
    }

編譯後, 會產生MyOuter.class 及MyOuter$MyInner.class. 使用時, 需先產生MyOuter的 outer物件, 再由outer.new 產生MyInner物件, MyInner物件的型態為MyOuter.MyInner
以上可以簡化為new MyOuter().new MyInner().foo();

內部類別的方法可以取得內部類別的方法 : this.x
也可取得外部類別的物件變數 x: MyOuter.this.x
取得外部類別的類別變數 ss : MyOuter.ss 或者 MyOuter.this.ss

區域類別

又稱方法類別, 是宣告在方法之內

    public class NestedClassTest {
        private int x;
        private static int y;
        public static void main(String[] args) {
            new NestedClassTest().set();
        }
        public void set(){
            final int xx=10;
            int yy=20;
            class MyInner{
                void foo(){
                    System.out.println("xx="+xx);
                    System.out.println("x="+NestedClassTest.this.x);
                    System.out.println("y="+NestedClassTest.this.y);
                }
            }
            new MyInner().foo();//定義完class才能new
        }
    }

建立方法內部類別物件必需寫在定義類別之後, 想在類別內取得方法區域變數, 必需是final才行, 比如上述的xx可以取得, 但yy不能取用. 另外外部類別的變數也可以取用

編譯時, 會產生NestedClassTest$1MyInner.class, 1是流水號

匿名類別

匿名類別是定義一個沒有名字的類別, 很常用到. 此種類別就是只用了一次後就不用了, 所以就懶的給名字了

    interface Pokemon{
        String attr="神奇寶貝";
        void skill();
        void move();
    }
    public class NestedClassTest {
        private int x;
        private static int y;
        public static void main(String[] args) {
            Pokemon p1=new Pokemon(){
                @Override
                public void skill() {
                    System.out.println("380V閃電攻擊");
                }
                @Override
                public void move() {
                    System.out.println("用爬的");
                }
                public void sound() {
                    System.out.println("皮卡丘");
                }
            };
            p1.skill();
            p1.move();
        }
    }

編譯後, 會產生NestedClassTest.$1.class
同樣的, 只能取得方法內的final 變數.

另外, 匿名類別可以實作自己的方法, 如public void sound(), 但無法用p1.sound()呼叫, 因為interface並沒有規定此功能

static 內部類別

物件實体化後, 放在Global區塊中, 不是放在Heap區. 本身沒有this可以指向外部內別, 所以無法使用外部物件變數.
但他本身是屬static的, 所以可以看到外部的類別變數

    public class NestedClassTest {
        private int x=7;//無法使用
        private static int y=9;
        static class MyInner{
            private int xx=77;
            private static int yy=99;
            public void foo(){
                System.out.println("static 內部類別的物件方法");
                System.out.println("y="+NestedClassTest.y);
                System.out.println("xx="+this.xx);
                System.out.println("yy="+yy);
            }
            public static void bar(){
                System.out.println("static 內部類別的類別方法");
                System.out.println("y="+NestedClassTest.y);
                System.out.println("yy="+yy);
            }
        }
        public static void main(String[] args) {
            NestedClassTest.MyInner in=new NestedClassTest.MyInner();
            in.foo();
            NestedClassTest.MyInner.bar();
        }
    }

實作時, 直接用
NestedClassTest.MyInner in=new NestedClassTest.MyInner();

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *