Trong Java hay Kotlin đều không có đa kế thừa, để khắc phục được điều này, các lập trình viên đã sử dụng interface
Mặc dù vẫn còn những hạn chế nhất định khi sử dụng interface nhưng qua nhiều phiên bản của Java và Kotlin, interface đã ngày càng mạnh mẽ theo thời gian
Hôm nay chúng ta sẽ cùng nhau nhìn xem interface sẽ có những tính năng gì nổi bật qua các phiên bản nhé
1. Interface trong Java 7
Trong Java 7, một interface chỉ có thể khai báo 2 loại :
- Hằng số (Constant Variables)
- Phương thức trừu tượng (Abstract Method)
1 2 3 4 5 6 7 | <span class="token keyword">interface</span> <span class="token class-name">OnCheckNumberListener</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> MAX_VALUE <span class="token operator">=</span> <span class="token number">1000</span><span class="token punctuation">;</span> <span class="token keyword">boolean</span> <span class="token function">isEvenNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Những phương thức của interface trong phiên bản này không được phép có thân hàm
Class implement interface đều phải cài đặt lại những phương thức trong interface
Bây giờ hãy cùng mình xét một bài toán nho nhỏ: Có 3 class A, B, C cùng implement interface
OnCheckNumberListener
Khi ấy, cả 3 class A, B, C
đều phải cài đặt phương thức isEvenNumber()
như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token keyword">implements</span> <span class="token class-name">OnCheckNumberListener</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isEvenNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> number <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">implements</span> <span class="token class-name">OnCheckNumberListener</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isEvenNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> number <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token keyword">implements</span> <span class="token class-name">OnCheckNumberListener</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isEvenNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> number <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Rõ ràng thấy, phương thức isEvenNumber()
bắt buộc phải viết lại ở cả 3 class A, B, C
nhưng nội dung của chúng thì giống nhau hoàn toàn
Nếu làm như vậy sẽ không thể tối ưu tính tái sử dụng mã nguồn được
Để giải quyết vấn đề trên, ở Java 7, chúng ta có thể tạo ra 1 lớp abstract
để cài đặt phương thức isEvenNumber()
1 2 3 4 5 6 7 8 | <span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">CheckNumber</span> <span class="token keyword">implements</span> <span class="token class-name">OnCheckNumberListener</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isEvenNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> number <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Và lúc này, ở 3 class A, B, C
sẽ không phải cài đặt lại phương thức isEvenNumber
khi extends class CheckNumber
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token keyword">extends</span> <span class="token class-name">CheckNumber</span><span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">extends</span> <span class="token class-name">CheckNumber</span><span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token keyword">extends</span> <span class="token class-name">CheckNumber</span><span class="token punctuation">{</span> <span class="token punctuation">}</span> |
Cách này có vẻ khả quan, nhưng hãy nhớ 1 điều rằng, Java không có hỗ trợ đa kế thừa, vì thế cách này chỉ khả thi khi A, B, C
chưa kế thừa lớp cha nào trước đó mà thôi.
2. Interface trong Java 8
Trong Java 8, ngoài hằng số và những phương thức abstract, chúng ta có thể khai báo những phương thức mặc định (default methods) và phương thức tĩnh (static methods)
- Hằng số (Constant Variables)
- Phương thức trừu tượng (Abstract Method)
- Phương thức mặc định (Default method)
- Phương thức tĩnh (Static method)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">interface</span> <span class="token class-name">OnCheckNumberListener</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> MAX_VALUE <span class="token operator">=</span> <span class="token number">1000</span><span class="token punctuation">;</span> <span class="token keyword">boolean</span> <span class="token function">isEvenNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">default</span> <span class="token keyword">boolean</span> <span class="token function">isOddNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> number <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> <span class="token keyword">boolean</span> <span class="token function">isNegativeNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> number <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Có lẽ với sự cải tiến này trong Java 8, chúng ta sẽ không cần phải tạo một lớp abstract class CheckNumber
nữa, mà có thể cài đặt luôn trong interface
1 2 3 4 5 6 7 8 | <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token keyword">implements</span> <span class="token class-name">OnCheckNumberListener</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isEvenNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">!</span><span class="token function">isOddNumber</span><span class="token punctuation">(</span>number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Tuy nhiên, không phải lúc nào hàm default của chúng ta cũng ngắn gọn, chúng có thể rất dài mà chúng ta muốn tách nó ra làm nhiều hàm nhỏ hơn
Khi ấy, vì chúng đang ở trong 1 interface nên những hàm tách ra ấy sẽ phải là public, mà điều này thì có vẻ không phải là thứ mà chúng ta mong muốn
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token keyword">interface</span> <span class="token class-name">OnCheckNumberListener</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> MAX_VALUE <span class="token operator">=</span> <span class="token number">1000</span><span class="token punctuation">;</span> <span class="token keyword">boolean</span> <span class="token function">isEvenNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">default</span> <span class="token keyword">boolean</span> <span class="token function">isOddNumber</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">checkFirst</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token function">checkSecond</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token function">checkThird</span><span class="token punctuation">(</span>number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">default</span> <span class="token keyword">boolean</span> <span class="token function">checkFirst</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">default</span> <span class="token keyword">boolean</span> <span class="token function">checkSecond</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">default</span> <span class="token keyword">boolean</span> <span class="token function">checkThird</span><span class="token punctuation">(</span><span class="token keyword">int</span> number<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> number <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
3. Interface trong Java 9
Java 9 đã giới thiệu các phương thức private
và phương thứcprivate static
trong các interface
.
- Hằng số
- Phương thức abstract
- Phương thức default
- Phương thức static
- Phương thức private
- Phương thức private static
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DBLogging</span> <span class="token punctuation">{</span> String MONGO_DB_NAME <span class="token operator">=</span> <span class="token string">"ABC_Mongo_Datastore"</span><span class="token punctuation">;</span> String NEO4J_DB_NAME <span class="token operator">=</span> <span class="token string">"ABC_Neo4J_Datastore"</span><span class="token punctuation">;</span> String CASSANDRA_DB_NAME <span class="token operator">=</span> <span class="token string">"ABC_Cassandra_Datastore"</span><span class="token punctuation">;</span> <span class="token keyword">default</span> <span class="token keyword">void</span> <span class="token function">logInfo</span><span class="token punctuation">(</span>String message<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">log</span><span class="token punctuation">(</span>message<span class="token punctuation">,</span> <span class="token string">"INFO"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">default</span> <span class="token keyword">void</span> <span class="token function">logWarn</span><span class="token punctuation">(</span>String message<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">log</span><span class="token punctuation">(</span>message<span class="token punctuation">,</span> <span class="token string">"WARN"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">default</span> <span class="token keyword">void</span> <span class="token function">logError</span><span class="token punctuation">(</span>String message<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">log</span><span class="token punctuation">(</span>message<span class="token punctuation">,</span> <span class="token string">"ERROR"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">default</span> <span class="token keyword">void</span> <span class="token function">logFatal</span><span class="token punctuation">(</span>String message<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">log</span><span class="token punctuation">(</span>message<span class="token punctuation">,</span> <span class="token string">"FATAL"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">log</span><span class="token punctuation">(</span>String message<span class="token punctuation">,</span> String msgPrefix<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Step 1: Connect to DataStore</span> <span class="token comment">// Step 2: Log Message with Prefix and styles etc.</span> <span class="token comment">// Step 3: Close the DataStore connection</span> <span class="token punctuation">}</span> <span class="token comment">// Any other abstract, static, default methods</span> <span class="token punctuation">}</span> |
Kết luận
Qua đó các bạn có thể thấy, Interface ngày càng được cải thiện qua nhiều phiên bản, hỗ trợ rất nhiều đặc biệt có thể khắc phục triệt để hơn nhước điểm không hỗ trợ đa kế thừa của nó
Ở bài tiếp theo, chúng ta hãy cùng nhau thảo luận xem Interface trong Kotlin sẽ có những điểm nào nổi bật nhé.