<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 混型 術語*混型*隨時間的推移好像擁有了無數的含義,但是其最基本的概念是混合多個類的能力,以產生一個可以表示混型中所有類型的類。這往往是你最后的手段,它將使組裝多個類變得簡單易行。 混型的價值之一是它們可以將特性和行為一致地應用于多個類之上。如果想在混型類中修改某些東西,作為一種意外的好處,這些修改將會應用于混型所應用的所有類型之上。正由于此,混型有一點*面向切面編程* (AOP) 的味道,而切面經常被建議用來解決混型問題。 ### C++ 中的混型 在 C++ 中,使用多重繼承的最大理由,就是為了使用混型。但是,對于混型來說,更有趣、更優雅的方式是使用參數化類型,因為混型就是繼承自其類型參數的類。在 C++ 中,可以很容易地創建混型,因為 C++ 能夠記住其模版參數的類型。 下面是一個 C++ 示例,它有兩個混型類型:一個使得你可以在每個對象中混入擁有一個時間戳這樣的屬性,而另一個可以混入一個序列號。 ```c++ // generics/Mixins.cpp #include <string> #include <ctime> #include <iostream> using namespace std; template<class T> class TimeStamped : public T { long timeStamp; public: TimeStamped() { timeStamp = time(0); } long getStamp() { return timeStamp; } }; template<class T> class SerialNumbered : public T { long serialNumber; static long counter; public: SerialNumbered() { serialNumber = counter++; } long getSerialNumber() { return serialNumber; } }; // Define and initialize the static storage: template<class T> long SerialNumbered<T>::counter = 1; class Basic { string value; public: void set(string val) { value = val; } string get() { return value; } }; int main() { TimeStamped<SerialNumbered<Basic>> mixin1, mixin2; mixin1.set("test string 1"); mixin2.set("test string 2"); cout << mixin1.get() << " " << mixin1.getStamp() << " " << mixin1.getSerialNumber() << endl; cout << mixin2.get() << " " << mixin2.getStamp() << " " << mixin2.getSerialNumber() << endl; } /* Output: test string 1 1452987605 1 test string 2 1452987605 2 */ ``` 在 `main()` 中, **mixin1** 和 **mixin2** 所產生的類型擁有所混入類型的所有方法。可以將混型看作是一種功能,它可以將現有類映射到新的子類上。注意,使用這種技術來創建一個混型是多么的輕而易舉。基本上,只需要聲明“這就是我想要的”,緊跟著它就發生了: ```c++ TimeStamped<SerialNumbered<Basic>> mixin1,mixin2; ``` 遺憾的是,Java 泛型不允許這樣。擦除會忘記基類類型,因此 > 泛型類不能直接繼承自一個泛型參數 這突顯了許多我在 Java 語言設計決策(以及與這些功能一起發布)中遇到的一大問題:處理一件事很有希望,但是當您實際嘗試做一些有趣的事情時,您會發現自己做不到。 ### 與接口混合 一種更常見的推薦解決方案是使用接口來產生混型效果,就像下面這樣: ```java // generics/Mixins.java import java.util.*; interface TimeStamped { long getStamp(); } class TimeStampedImp implements TimeStamped { private final long timeStamp; TimeStampedImp() { timeStamp = new Date().getTime(); } @Override public long getStamp() { return timeStamp; } } interface SerialNumbered { long getSerialNumber(); } class SerialNumberedImp implements SerialNumbered { private static long counter = 1; private final long serialNumber = counter++; @Override public long getSerialNumber() { return serialNumber; } } interface Basic { void set(String val); String get(); } class BasicImp implements Basic { private String value; @Override public void set(String val) { value = val; } @Override public String get() { return value; } } class Mixin extends BasicImp implements TimeStamped, SerialNumbered { private TimeStamped timeStamp = new TimeStampedImp(); private SerialNumbered serialNumber = new SerialNumberedImp(); @Override public long getStamp() { return timeStamp.getStamp(); } @Override public long getSerialNumber() { return serialNumber.getSerialNumber(); } } public class Mixins { public static void main(String[] args) { Mixin mixin1 = new Mixin(), mixin2 = new Mixin(); mixin1.set("test string 1"); mixin2.set("test string 2"); System.out.println(mixin1.get() + " " + mixin1.getStamp() + " " + mixin1.getSerialNumber()); System.out.println(mixin2.get() + " " + mixin2.getStamp() + " " + mixin2.getSerialNumber()); } } /* Output: test string 1 1494331663026 1 test string 2 1494331663027 2 */ ``` **Mixin** 類基本上是在使用*委托*,因此每個混入類型都要求在 **Mixin** 中有一個相應的域,而你必須在 **Mixin** 中編寫所有必需的方法,將方法調用轉發給恰當的對象。這個示例使用了非常簡單的類,但是當使用更復雜的混型時,代碼數量會急速增加。 ### 使用裝飾器模式 當你觀察混型的使用方式時,就會發現混型概念好像與*裝飾器*設計模式關系很近。裝飾器經常用于滿足各種可能的組合,而直接子類化會產生過多的類,因此是不實際的。 裝飾器模式使用分層對象來動態透明地向單個對象中添加責任。裝飾器指定包裝在最初的對象周圍的所有對象都具有相同的基本接口。某些事物是可裝飾的,可以通過將其他類包裝在這個可裝飾對象的四周,來將功能分層。這使得對裝飾器的使用是透明的——無論對象是否被裝飾,你都擁有一個可以向對象發送的公共消息集。裝飾類也可以添加新方法,但是正如你所見,這將是受限的。 裝飾器是通過使用組合和形式化結構(可裝飾物/裝飾器層次結構)來實現的,而混型是基于繼承的。因此可以將基于參數化類型的混型當作是一種泛型裝飾器機制,這種機制不需要裝飾器設計模式的繼承結構。 前面的示例可以被改寫為使用裝飾器: ```java // generics/decorator/Decoration.java // {java generics.decorator.Decoration} package generics.decorator; import java.util.*; class Basic { private String value; public void set(String val) { value = val; } public String get() { return value; } } class Decorator extends Basic { protected Basic basic; Decorator(Basic basic) { this.basic = basic; } @Override public void set(String val) { basic.set(val); } @Override public String get() { return basic.get(); } } class TimeStamped extends Decorator { private final long timeStamp; TimeStamped(Basic basic) { super(basic); timeStamp = new Date().getTime(); } public long getStamp() { return timeStamp; } } class SerialNumbered extends Decorator { private static long counter = 1; private final long serialNumber = counter++; SerialNumbered(Basic basic) { super(basic); } public long getSerialNumber() { return serialNumber; } } public class Decoration { public static void main(String[] args) { TimeStamped t = new TimeStamped(new Basic()); TimeStamped t2 = new TimeStamped( new SerialNumbered(new Basic())); //- t2.getSerialNumber(); // Not available SerialNumbered s = new SerialNumbered(new Basic()); SerialNumbered s2 = new SerialNumbered( new TimeStamped(new Basic())); //- s2.getStamp(); // Not available } } ``` 產生自泛型的類包含所有感興趣的方法,但是由使用裝飾器所產生的對象類型是最后被裝飾的類型。也就是說,盡管可以添加多個層,但是最后一層才是實際的類型,因此只有最后一層的方法是可視的,而混型的類型是所有被混合到一起的類型。因此對于裝飾器來說,其明顯的缺陷是它只能有效地工作于裝飾中的一層(最后一層),而混型方法顯然會更自然一些。因此,裝飾器只是對由混型提出的問題的一種局限的解決方案。 ### 與動態代理混合 可以使用動態代理來創建一種比裝飾器更貼近混型模型的機制(查看 [類型信息](book/19-Type-Information.md) 一章中關于 Java 的動態代理如何工作的解釋)。通過使用動態代理,所產生的類的動態類型將會是已經混入的組合類型。 由于動態代理的限制,每個被混入的類都必須是某個接口的實現: ```java // generics/DynamicProxyMixin.java import java.lang.reflect.*; import java.util.*; import onjava.*; import static onjava.Tuple.*; class MixinProxy implements InvocationHandler { Map<String, Object> delegatesByMethod; @SuppressWarnings("unchecked") MixinProxy(Tuple2<Object, Class<?>>... pairs) { delegatesByMethod = new HashMap<>(); for(Tuple2<Object, Class<?>> pair : pairs) { for(Method method : pair.a2.getMethods()) { String methodName = method.getName(); // The first interface in the map // implements the method. if(!delegatesByMethod.containsKey(methodName)) delegatesByMethod.put(methodName, pair.a1); } } } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); Object delegate = delegatesByMethod.get(methodName); return method.invoke(delegate, args); } @SuppressWarnings("unchecked") public static Object newInstance(Tuple2... pairs) { Class[] interfaces = new Class[pairs.length]; for(int i = 0; i < pairs.length; i++) { interfaces[i] = (Class)pairs[i].a2; } ClassLoader cl = pairs[0].a1.getClass().getClassLoader(); return Proxy.newProxyInstance(cl, interfaces, new MixinProxy(pairs)); } } public class DynamicProxyMixin { public static void main(String[] args) { Object mixin = MixinProxy.newInstance( tuple(new BasicImp(), Basic.class), tuple(new TimeStampedImp(), TimeStamped.class), tuple(new SerialNumberedImp(), SerialNumbered.class)); Basic b = (Basic)mixin; TimeStamped t = (TimeStamped)mixin; SerialNumbered s = (SerialNumbered)mixin; b.set("Hello"); System.out.println(b.get()); System.out.println(t.getStamp()); System.out.println(s.getSerialNumber()); } } /* Output: Hello 1494331653339 1 */ ``` 因為只有動態類型而不是靜態類型才包含所有的混入類型,因此這仍舊不如 C++ 的方式好,因為可以在具有這些類型的對象上調用方法之前,你被強制要求必須先將這些對象向下轉型到恰當的類型。但是,它明顯地更接近于真正的混型。 為了讓 Java 支持混型,人們已經做了大量的工作朝著這個目標努力,包括創建了至少一種附加語言( Jam 語言),它是專門用來支持混型的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看