01/10/2018, 08:40

1 Số câu hỏi về OOP mong được giải đáp

em vừa học xong về oop có 1 vài thắc mắc thế này

  1. ta có thể nói inteface là 1 class thuần ảo ( abstract ) được không ??
  2. điểm khác biệt giữa abstract và inteface có phải là inteface có thể giải quyết vấn đề đa thừa kế , cho nên khi sử dụng nó để thể hiện tính đa hình sẽ tốt hơn abstract class ( 1 đối tượng có thể có nhiều kiểu )
  3. mình thấy người ta hay dùng inteface và abstract class để khai báo 1 kiểu chung cho các class có cùng chức năng hay cùng loại , vậy có thể dùng inteface để thay thế cho abstract được không??
Đăng Trần viết 10:46 ngày 01/10/2018

Anh thấy em nên tìm hiểu kỹ vấn đề cơ bản trước.

  1. Nó là cái gì.
  2. Tại sao phải dùng nó.
  3. Khi nào thì dùng nó.
    Mọi người cứ so sánh thành ra rối. Nghĩ lung tung, học từng cái rành rồi mới so sánh thì rõ như ban ngày thôi.
    Sau đó nghiên cứu các ví dụ căn bản em sẽ tự trả lời được câu hỏi của mình. Rất nhiều diễn đàn tiếng Anh hướng dẫn vô cùng dễ hiểu và ngôn ngữ sử dụng rất phổ thông về vấn đề này. Nếu em làm được C# anh khuyên em nên đọc trên C# Corner vì trang này hướng dẫn rất nhẹ nhàng, code dễ hiểu.
Hidan viết 10:56 ngày 01/10/2018
  1. Nó là cái gì.2. Tại sao phải dùng nó.3. Khi nào thì dùng nó.

giống câu nói của thầy mh, thêm dùng nó như thế nào nữa :v ,

Pete Houston viết 10:53 ngày 01/10/2018

ta có thể nói inteface là 1 class thuần ảo ( abstract ) được không ??

Không, ngược lại thì đúng.

điểm khác biệt giữa abstract và inteface có phải là inteface có thể giải quyết vấn đề đa thừa kế

Không đúng. Đa kế thừa là lớp con có tất cả các đặc điểm và khả năng sử dụng các phương thức của các lớp cha, còn interface rằng buộc về phương thức. Vậy nếu đa kế thừa từ nhiều lớp cha có cùng phương thức, cùng thuộc tính thì lớp con quyết định thế nào?

mình thấy người ta hay dùng inteface và abstract class để khai báo 1 kiểu chung cho các class có cùng chức năng hay cùng loại , vậy có thể dùng inteface để thay thế cho abstract được không??

abstract dùng để tạo thiết lập chung, các lớp con bị ép theo một dòng máu, không linh hoạt.
interface chỉ rằng buộc về phương thức của nhóm, nên hoàn toàn linh hoạt.

Always Code To Interfaces.

Tham khảo khóa học này để tìm hiểu rõ hơn về các đặc tính và bản chất của OOP: https://kodemate.com/series/phat-trien-tu-duy-lap-trinh-huong-doi-tuong-voi-java

Cong 5 viết 10:41 ngày 01/10/2018

cảm ơn bạn nhiều…
sao ở đây : http://gockinhnghiem.com/2015/07/12/abstract-class-vs-interface/
nó lại ghi là inteface giải quyết được vấn đề đa thừa kế nhỉ , mình cũng cảm thấy sai khi nói inteface là đa thừa kế vì nó sử dụng từ implement là bổ sung chứ không phải từ extend

nếu mục đích tạo ra abstract class là để tạo thiết lập chung cho các class con , vậy mục đích khi người ta tạo ra interface là gì ?

Cong 5 viết 10:54 ngày 01/10/2018

thì em đã đọc và tự suy nghĩ theo ý của mình ko biết đúng hay ko nên mới lên đây hỏi , chứ dốt mà còn giấu nữa thì bao giờ mới giỏi được ??

Hung Nguyen viết 10:52 ngày 01/10/2018
  1. Do cách đặt tên gọi thôi đó ban, bạn hiểu thế cũng ko sai, class nào thuần ảo (tức là chưa implement gì) thì trong Java người ta đặt tên là interface. Trong 1 số ngôn ngữ bạn sẽ thấy loại bỏ hoàn toàn khái niệm abstract class (golang, swift …)
    2 . Đúng, vì 1 class trong Java thừa kế được từ nhiều interface nên gọi là giải quyểt được vụ đa thừa kế.
  2. Được, thực tế các ngôn ngữ mới như swift, golang đều dùng interface để khai báo kiểu. Còn gọi là Protocol oriented programing.
Cong 5 viết 10:46 ngày 01/10/2018

Vậy nếu đa kế thừa từ nhiều lớp cha có cùng phương thức, cùng thuộc tính thì lớp con quyết định thế nào?

vì sử dụng interface nên chính các lớp con sẽ định nghĩa các phương thức đó , còn interface chỉ chứa các phương thức ảo và interface không thể tạo thể hiện được ( 2 điều này đã giải quyết được câu hỏi trên ) , và ở đây interface nó giúp ta loại bỏ mặt hạn chế của đa thừa kế vừa giúp ta có được những tính chất tốt của đa thừa kế (
Interface has 2 meanings or functions in JAVA

  1. it’s used to define a bridge to another object (or class)
  2. it’s the backdoor to circumvent the Single Inheritance.)
Pete Houston viết 10:41 ngày 01/10/2018

vì sử dụng interface nên chính các lớp con sẽ định nghĩa các phương thức đó , còn interface chỉ chứa các phương thức ảo và interface không thể tạo thể hiện được ( 2 điều này đã giải quyết được câu hỏi trên ) , và ở đây interface nó giúp ta loại bỏ mặt hạn chế của đa thừa kế vừa giúp ta có được những tính chất tốt của đa thừa kế

Tham khảo bài toán diamond problem.

Interface has 2 meanings or functions in JAVA

Interface has only one and only one mean: to morph into anything we want it to behave correspondingly.

Đăng Trần viết 10:49 ngày 01/10/2018

Biết ngay, đi sâu vô cái vụ này mất thời gian tranh luận lắm. Vẫn hóng để anh em làm rõ luôn mai mốt khỏi bàn nữa.
Thả hết tym cho trả lời có đầu tư và đúng lý thuyết.

Phan Hoàng viết 10:45 ngày 01/10/2018

Mình nghĩ @Hung_Nguyen12 trả lời chuẩn rồi. Còn vụ tranh luận đa thừa kế hay thuần ảo … theo mình không quan trọng lắm ^^ (hầu hết các tài liệu đều gọi interface là thuần abstract và dùng cho vụ đa thừa kế).

Còn vụ what, why, when thì mình giải thích qua 1 chút ở 1 số case

Case1: Giả sử bạn viết CRUD cho product

public void addProduct(Product p){
  //code here
}

Giờ bạn muốn làm unit-test thì sao? Bạn sẽ tạo ra 1 p = new Product(); //fake. Thế nhưng nếu 1 người nào đó dùng hàm của bạn, nhưng không muốn bị bó buộc vào object Product đó, vì họ chẳng biết Product cần phải được tạo ra như thế nào (giả sử lib của bạn đã được compile). So sánh với:

public void addProduct(IProduct p){
   //code here
}

Giờ mình gom những cái gì thực sự cần thiết ra 1 interface, họ có thể tự truyền 1 new MockProduct implement IProduct là được, dễ dàng hơn rất nhiều phải không? Nguyên lý này được gọi là Liskov Duck (chữ L trong SOLID), nghĩa là bạn thiết kế ra 1 con vịt tiêu chuẩn mà có thể gắn pin AA, con thỏ, con ó … vào được, miễn là pin đó phù hợp với thiết kế IPin. Việc gom tạo interface cũng giúp người sử dụng lib dễ dàng hiểu các API nào mình expose cho họ, cũng giống như bạn cầm cái điều khiển quạt, bạn bấm 1,2,3 … chứ đâu cần biết trong cái điều khiển đó, nguyên lý hoạt động ra sau (ví dụ, bấm 1, tạo xung điện, kết nối bộ phần phát hồng ngoại, gửi tín hiệu hồng ngoại, quạt nhận tín hiệu hồng ngoại, chuyển đổi xung, biến trở ngắt để cuộn cảm chuyển mạch sang cảm ứng điện mới …Who cares?)

Case2: trong lập trình sự kiện (event-driven), giả sử sự kiện click

btnCheckListener = new  OnClickListener {
   click(event){
      //implement ở đây
   }
}
btnCheck.setOnClickListener(btnCheckListener);
interface OnClickListener {
   click(event);
}

Việc truyền 1 class implement OnClickListener vì trong cái event-loop nghe sự kiện, mình sẽ phải gọi cái action xử lý khi có sự kiện đó. Lúc đó, mình gọi action nào nếu mình không qui định trong inteface. Việc qui định click function sẽ giúp mình thống nhất cách gọi (chứ ông thì đặt click, ông đặt push, … mình phải wrap hết các trường hợp đó có mà a ma toi)

//event-loop
while(true){
   listener.click(e);
}

Case3: vụ đa thừa kế (thực tế thì thừa kế mỗi tên hàm, chứ nội dung thì có thừa kế đâu). Ví dụ mình muốn viết 1 collection.

public class MyCollection implements Serializable, Iterable, Traversable {
 public void iterate(){};
 public void next(){};
 public void prev(){};

 public void last(){};
 public void first(){};
 public void move(index i){};
}

Rõ ràng mình cần MyCollection của mình phải iterate được, phải move qua move lại giữa các element, … thế nên mình implement các Interface chuẩn thì: thứ nhất không bỏ sót tính năng, thứ hai collection này sau có thể dùng như các collection chuẩn khác (người dùng lib đỡ phải học)

Interface được dùng trong rất nhiều design pattern kiểu Protocol Oriented (tức là mình chỉ cần hiểu giao thức, còn phía trong đâu cần biết) như Command, Repository …

Phan Hoàng viết 10:52 ngày 01/10/2018

Còn abstract class thì mình lấy case này nhé, bạn muốn thiết kế 1 Gateway package (thanh toán). Có rất nhiều gateway như Paypal, GoogleCheckout, … Có tới hàng nghìn gateway, và bất cứ gateway nào cũng có các function kiểu như getAccInfo, draw, deposit, transferInternal …

Thế nhưng các function như getAccInfo hay tranferInternal ở cổng nào cũng giống nhau, chỉ là lấy thông tin 1 acc hay chuyển tiền từ 1 acc nào đó sang 1 acc khác, … Còn các funftion kia thì nghiệp vụ khác, mỗi ngân hàng 1 kiểu. … Nếu thiết kế Interface thì sẽ bị duplicate các function giống nhau. Thế nên thiết kế abtract hợp lý hơn

abstract class Gateway {
   public void getAccInfo(){
      //code
   }
  
   abstract void transfer(acc1, acc2);
}

public class Paypal extends Gateway {}
public class GCheckout extends Gateway {}

abstract chính là kiểu lai giữa class thuần và interface thuần (mixed). Thường abstract hay dùng trong Factory pattern. Ví dụ, mình gọi Paypal p = GatewayBuilder.build(‘Paypal’);

Còn vụ từ khoá implements hay extends chỉ là để bộ compiler hiểu thôi, chứ vào memory thì là object code hết (1 số ngôn ngữ còn chẳng có từ khoá này, cứ dấu : mà tương cho đỡ phải viết nhiều chữ ^^). Với lại, chả nhẽ viết extends and implement Gateway (abstract) ^^

Cũng như tất cả các ngành sản xuất khác, việc làm abstract (tính trong suốt) thường là trending. Các tầng, các lớp không cần biết các tầng phía dưới thế nào, chỉ cần mày cung cấp đủ data để tao hiển thị (mày có lấy từ MySQL, từ Webservice, rồi mày có dungf CRUD hay CQ-RS thì kệ bố mày, tao méo quan tâm ^^). Ông làm core thì cứ làm core, tao làm shell thì cứ đúng chuản tao làm, mày chưa xong thì tao cứ mặc định là data sẽ là như thế để code, chứ dek ai đợi được ông code xong.

Đấy, việc design theo chuẩn giúp làm //, giúp isolate công việc của nhau, của các tầng. Ông sản xuất giao hàng, ông kho chỉ cần biết là hàng nó kích thước vậy, khối lượng vậy rồi bố trí lên kệ, ông giao nhận thì chỉ cần nhận gói hàng, xem ký hiệu dễ vỡ hay … gì đó rồi giao cho khách … Mỗi ông 1 công đoạn, không cần biết công việc quá của nhau, chỉ cần biết in-out là đủ.

Đăng Trần viết 10:42 ngày 01/10/2018

Thế giới cần những người như bạn.

Reoteu Ray viết 10:43 ngày 01/10/2018

khá rõ ràng , thanks bạn …

Phan Hoàng viết 10:52 ngày 01/10/2018

Thực ra hôm qua vừa ngủ gật, vừa viết vội nên cũng nhiều chỗ bị lỗi typo. Thank mọi người đã động viên ^^

Interns viết 10:48 ngày 01/10/2018

Vậy nếu đa kế thừa từ nhiều lớp cha có cùng phương thức, cùng thuộc tính thì lớp con quyết định thế nào?

Dùng fully qualified name được mà nhỉ

class Demo : Interface1, Interface2
{
  public static void Main()
  {
    Interface1 refInterface1 = new Demo();
    refInterface1.DoSomething();

    Interface2 refInterface2 = new Demo();
    refInterface2.DoSomething();
  }

  void Interface1.DoSomething()
  {
     System.Console.WriteLine("In Interface1");
  }  

  void Interface2.DoSomething()
  {
     System.Console.WriteLine("In Interface2");
  }  

}

interface Interface1
{
  void DoSomething();
}

interface Interface2
{
  void DoSomething();
}
Pete Houston viết 10:44 ngày 01/10/2018

Dùng fully qualified name được mà nhỉ

Nếu đã là kế thừa thì phải biết chắc ghi gọi một method từ lớp cha thì phải biết thực thi method nào; nếu truy xuất thế này thì lại ko đúng bản chất kế thừa.

Vì thế mà trong Java, đa kế thừa ko thực hiện được. Cách giải quyết là dùng interface cho phép tạo rằng buộc về khả năng trong từng nhóm implementation.

Trong C#, tương tự như Java, nhưng thay vì dùng chung dấu : cho cả inheritance và interface contract, nên nếu chỉ tìm hiểu qua C# sẽ rất hay bị hiểu nhầm là đa kế thừa.

Luân Hồ viết 10:44 ngày 01/10/2018

1 . ta có thể nói inteface là 1 class thuần ảo ( abstract ) được không ??
Không vì interface là interface , abstract class là abstract class
2. điểm khác biệt giữa abstract và inteface có phải là inteface có thể giải quyết vấn đề đa thừa kế , cho nên khi sử dụng nó để thể hiện tính đa hình sẽ tốt hơn abstract class ( 1 đối tượng có thể có nhiều kiểu )
Đúng là interface khác abstract class ở chỗ nó cho đa kế thừa , nhưng chưa đủ . Interface không chứa các thuộc tính và phương thức có nội dung còn abstract class thì có , do vậy nếu chỉ dùng interface mà không dùng abstract class thì sẽ phải khởi tạo các thuộc tính giống nhau và các phương thức có nội dung nhiều lần.
3.mình thấy người ta hay dùng inteface và abstract class để khai báo 1 kiểu chung cho các class có cùng chức năng hay cùng loại , vậy có thể dùng inteface để thay thế cho abstract được không??

Bài liên quan
0