總結java的interface和abstract class – JAVA編程語言程序開發技術文章

 
先說說interface和abstract method語法中需要註意的地方。


Interface:


1. An interface can contain fields, but these are implicitly static and final.


2. You can choose to explicitly declare the methods in an interface as public, but they are public even if you don’t say it.


3. Interface cannot define static method


 


Abstract:


1. 一個類中如果所有的方法都有實現,我們仍然可以定義這個類為abstract class


2. abstract和static不能放在一起定義方法。


 


Interface和Abstract class的實踐


1. interface適合定義mixins(不知道mixin怎麼翻譯,它指窄接口,隻定義specific contract).


java不能多重繼承。如果想達到多重繼承的效果,需要借助“多重實現”interface. interface的一個典型用法是定義小接口。比如Comparable。這樣它的實現成本比較小,一個class比較容易mixin多個interface。


2. 如果interface不是mixin, 而是大一點的接口。


effective java, 2nd edition有精彩的闡述,對於大接口,我們往往使用skeletal implementation class. 舉個例子:


   1: // Concrete implementation built atop skeletal implementation
   2: static List<Integer> intArrayAsList(final int[] a) {
   3: if (a == null)
   4: throw new NullPointerException();
   5: return new AbstractList<Integer>() {
   6: public Integer get(int i) {
   7: return a[i];  // Autoboxing (Item 5)
   8: }
   9: @Override public Integer set(int i, Integer val) {
  10: int oldVal = a[i];
  11: a[i] = val;     // Auto-unboxing
  12: return oldVal;  // Autoboxing
  13: }
  14: public int size() {
  15: return a.length;
  16: }
  17: };
  18: }


new AbstractList<Integer>就是在應用Skeletal implementation. 有兩個好處:


a) 它使實現接口更方便瞭


b) If, in a subsequent release, you want to add a new method to an abstract class, you can always add a concrete method containing a reasonable default implementation. All existing implementations of the abstract class will then provide the new method. This does not work for interfaces.


跟interface相關的還有一個話題是wrapper class,也很精彩,它是把繼承轉成合成的方式,應用瞭decorater模式的思想. 在書裡的第16章介紹。


   1: // Wrapper class – uses composition in place of inheritance
   2: public class InstrumentedSet<E> extends ForwardingSet<E> {
   3:     private int addCount = 0;
   4:     public InstrumentedSet(Set<E> s) {
   5:         super(s);
   6:     }
   7:     @Override public boolean add(E e) {
   8:         addCount++;
   9:         return super.add(e);
  10:     }
  11:     @Override public boolean addAll(Collection<? extends E> c) {
  12:         addCount += c.size();
  13:         return super.addAll(c);
  14:     }
  15:     public int getAddCount() {
  16:         return addCount;
  17:     }
  18: }
  19: // Reusable forwarding class
  20: public class ForwardingSet<E> implements Set<E> {
  21:     private final Set<E> s;
  22:     public ForwardingSet(Set<E> s) { this.s = s; }
  23:     public void clear()               { s.clear();            }
  24:     public boolean contains(Object o) { return s.contains(o); }
  25:     public boolean isEmpty()          { return s.isEmpty();   }
  26:     public int size()                 { return s.size();      }
  27:     public Iterator<E> iterator()     { return s.iterator();  }
  28:     public boolean add(E e)           { return s.add(e);      }
  29:     public boolean remove(Object o)   { return s.remove(o);   }
  30:     public boolean containsAll(Collection<?> c)
  31:                                    { return s.containsAll(c); }
  32:     public boolean addAll(Collection<? extends E> c)
  33:                                    { return s.addAll(c);      }
  34:     public boolean removeAll(Collection<?> c)
  35:                                    { return s.removeAll(c);   }
  36:     public boolean retainAll(Collection<?> c)
  37:                                    { return s.retainAll(c);   }
  38:     public Object[] toArray()          { return s.toArray();  }
  39:     public <T> T[] toArray(T[] a)      { return s.toArray(a); }
  40:     @Override public boolean equals(Object o)
  41:                                        { return s.equals(o);  }
  42:     @Override public int hashCode()    { return s.hashCode(); }
  43:     @Override public String toString() { return s.toString(); }
  44: }


使用它的客戶端程序:


   1: Set<Date> s = new InstrumentedSet<Date>(new TreeSet<Date>(cmp));
   2: Set<E> s2 = new InstrumentedSet<E>(new HashSet<E>(capacity));


 


3. 人人都說 面向接口編程,很多時候矯枉過正瞭, 搞得接口漫天飛。interface常常是重構出來的,而不總是設計出來的。程序分層中,越是靠近底層的程序,越傾向於需要接口,越靠近頂層的程序,對接口的需求傾向於越小。如果你明知道以後不太可能提供另一套實現,提前寫個接口擺那裡也沒啥意義,盡管定義接口的成本很低。如果你擔心一旦有一天確實提供瞭另一套實現,重構code也不會很麻煩。隻要遵守瞭單一職責原則和迪米特法則。迪米特法則的一種表述方式是:talk only to your immediate friends

發佈留言