2010-01-17 99 views
24

Tôi là người mới đến OOP. Mặc dù tôi hiểu sự đa hình là gì, nhưng tôi không thể sử dụng nó. Tôi có thể có các chức năng với tên khác. Tại sao tôi nên cố gắng thực hiện đa hình trong ứng dụng của mình.Ý nghĩa thực sự (sử dụng) của đa hình

+1

Hãy xem: http://stackoverflow.com/questions/409969/polymorphism-define-in-just- hai câu – Zaki

+1

Tôi cố gắng trả lời câu hỏi này tại http://stackoverflow.com/questions/5854581/polymorphism-in-c/5854862#5854862 - mặc dù điều này tập trung vào hỗ trợ C++ cho đa hình và các ngôn ngữ khác có thể có một phụ hoặc siêu thiết lập các cơ sở được đề cập. Tôi nghĩ rằng nó bao gồm các khái niệm khá tốt mặc dù ... hy vọng nó sẽ giúp. –

Trả lời

21

Câu trả lời cổ điển: Hãy tưởng tượng một lớp cơ sở Shape. Nó hiển thị phương thức GetArea. Hãy tưởng tượng một lớp học Square và một lớp học Rectangle và lớp học Circle. Thay vì tạo các phương thức riêng biệt GetSquareArea, GetRectangleAreaGetCircleArea, bạn chỉ cần thực hiện một phương thức trong mỗi lớp dẫn xuất. Bạn không cần phải biết lớp con chính xác của Shape bạn sử dụng, bạn chỉ cần gọi GetArea và bạn nhận được kết quả của mình, độc lập với loại bê tông nào.

Có một cái nhìn tại mã này:

#include <iostream> 
using namespace std; 

class Shape 
{ 
public: 
    virtual float GetArea() = 0; 
}; 

class Rectangle : public Shape 
{ 
public: 
    Rectangle(float a) { this->a = a; } 
    float GetArea() { return a * a; } 
private: 
    float a; 
}; 

class Circle : public Shape 
{ 
public: 
    Circle(float r) { this->r = r; } 
    float GetArea() { return 3.14f * r * r; } 
private: 
    float r; 
}; 

int main() 
{ 
    Shape *a = new Circle(1.0f); 
    Shape *b = new Rectangle(1.0f); 

    cout << a->GetArea() << endl; 
    cout << b->GetArea() << endl; 
} 

Một điều quan trọng cần lưu ý ở đây là - bạn không cần phải biết chính xác loại của lớp bạn đang sử dụng, chỉ cần loại cơ sở, và bạn sẽ nhận được kết quả đúng. Điều này rất hữu ích trong các hệ thống phức tạp hơn.

Hãy học tập thú vị!

+0

Tôi nghĩ rằng hình chữ nhật/vòng tròn là một ví dụ nghèo vì "vấn đề hình elip cổ điển" nó tự nhiên dẫn đến. Giả sử bạn có một lớp hình chữ nhật mà bạn có thể thiết lập chiều rộng và chiều cao, sau đó một lớp hình vuông mở rộng từ hình chữ nhật mà thiết lập chiều rộng và chiều cao cùng một lúc. Sau đó rect.Width * = 2; rect.Height * = 2; thực sự cung cấp cho bạn 4x độ dài cạnh. – Warty

+0

@Warty cho bất kỳ ai muốn đọc thêm về tìm kiếm này cho Nguyên tắc thay thế Liskov. –

1

Đa hình cho phép bạn viết mã sử dụng các đối tượng. Sau đó bạn có thể tạo các lớp mới mà mã hiện tại của bạn có thể sử dụng mà không cần sửa đổi.

Ví dụ: giả sử bạn có chức năng Lib2Groc(vehicle) hướng một phương tiện từ thư viện đến cửa hàng tạp hóa. Nó cần phải nói với xe để rẽ trái, vì vậy nó có thể gọi TurnLeft() trên đối tượng xe trong số những thứ khác. Sau đó, nếu ai đó sau đó phát minh ra một chiếc xe mới, giống như một chiếc mô-tô thủy phi cơ, nó có thể được sử dụng bởi Lib2Groc mà không cần sửa đổi.

0

Bạn không cần đa hình.

Cho đến khi bạn thực hiện.

Sau đó, friggen tuyệt vời.

Câu trả lời đơn giản mà bạn sẽ xử lý nhiều lần:

Ai đó cần phải trải qua một bộ sưu tập nội dung. Giả sử họ yêu cầu một bộ sưu tập kiểu MySpecializedCollectionOfAwesome. Nhưng bạn đã xử lý các trường hợp tuyệt vời của bạn như Danh sách. Vì vậy, bây giờ, bạn sẽ phải tạo ra một thể hiện của MSCOA và điền nó với mỗi trường hợp của Awesome bạn có trong danh sách của bạn < T>. Đau lớn ở mông, phải không?

Vâng, nếu họ yêu cầu một số An ninh tuyệt vời, bạn có thể trao cho họ một trong số MANY bộ sưu tập Thú vị nhất. Bạn có thể giao cho họ một mảng (Awesome []) hoặc Danh sách (Danh sách < Awesome>) hoặc bộ sưu tập tuyệt vời của ELSE tuyệt vời hoặc bất cứ điều gì bạn giữ cho Awesome của bạn trong đó triển khai IEnumerable < T>.

Sức mạnh của đa hình cho phép bạn nhập an toàn, nhưng đủ linh hoạt để bạn có thể sử dụng một cá thể nhiều cách khác nhau mà không tạo hàng tấn mã đặc biệt xử lý loại này hoặc loại đó.

7

Trong ngôn ngữ được nhập đúng, đa hình là quan trọng để có danh sách/bộ sưu tập/mảng đối tượng thuộc các loại khác nhau. Điều này là do danh sách/mảng được tự đánh máy để chỉ chứa các đối tượng thuộc loại chính xác.

Hãy tưởng tượng ví dụ, chúng tôi đã điều sau đây:

// the following is pseudocode M'kay: 
class apple; 
class banana; 
class kitchenKnife; 

apple foo; 
banana bar; 
kitchenKnife bat; 

apple *shoppingList = [foo, bar, bat]; // this is illegal because bar and bat is 
             // not of type apple. 

Để giải quyết điều này:

class groceries; 
class apple inherits groceries; 
class banana inherits groceries; 
class kitchenKnife inherits groceries; 

apple foo; 
banana bar; 
kitchenKnife bat; 

groceries *shoppingList = [foo, bar, bat]; // this is OK 

Ngoài ra nó làm cho xử lý danh sách các mục đơn giản hơn. Nói ví dụ như tất cả cửa hàng tạp hóa thực hiện các phương pháp price(), chế biến này là dễ dàng:

int total = 0; 
foreach (item in shoppingList) { 
    total += item.price(); 
} 

Hai tính năng này là cốt lõi của những gì đa hình không.

4

Đa hình là nền tảng của Lập trình hướng đối tượng. Nó có nghĩa là một đối tượng có thể có như một dự án khác. Vì vậy, làm thế nào về đối tượng có thể trở nên khác, có thể của nó thông qua sau

  1. Inheritance
  2. hành vi
  3. Overriding/Thực hiện mẹ Lớp
  4. Runtime binding Object

Một trong những lợi thế chính của nó là chuyển đổi triển khai. Giả sử bạn đang mã hóa một ứng dụng cần nói chuyện với cơ sở dữ liệu. Và bạn xảy ra để xác định một lớp mà hoạt động cơ sở dữ liệu này cho bạn và dự kiến ​​của nó để làm một số hoạt động như Add, Delete, Modify. Bạn biết rằng cơ sở dữ liệu có thể được thực hiện theo nhiều cách, có thể nói đến hệ thống tệp hoặc máy chủ RDBM như MySQL, v.v ... Vì vậy, bạn là lập trình viên, sẽ định nghĩa một giao diện mà bạn có thể sử dụng, chẳng hạn như ...

public interface DBOperation { 
    public void addEmployee(Employee newEmployee); 
    public void modifyEmployee(int id, Employee newInfo); 
    public void deleteEmployee(int id); 
} 

Bây giờ bạn có thể có nhiều triển khai, cho phép nói rằng chúng ta có một cho RDBMS và khác cho hệ thống file trực tiếp

public class DBOperation_RDBMS implements DBOperation 
    // implements DBOperation above stating that you intend to implement all 
    // methods in DBOperation 
    public void addEmployee(Employee newEmployee) { 
      // here I would get JDBC (Java's Interface to RDBMS) handle 
      // add an entry into database table. 
    } 
    public void modifyEmployee(int id, Employee newInfo) { 
      // here I use JDBC handle to modify employee, and id to index to employee 
    } 
    public void deleteEmployee(int id) { 
      // here I would use JDBC handle to delete an entry 
    } 
} 

cho phép có thực hiện cơ sở dữ liệu file System

public class DBOperation_FileSystem implements DBOperation 
    public void addEmployee(Employee newEmployee) { 
      // here I would Create a file and add a Employee record in to it 
    } 
    public void modifyEmployee(int id, Employee newInfo) { 
      // here I would open file, search for record and change values 
    } 
    public void deleteEmployee(int id) { 
      // here I search entry by id, and delete the record 
    } 
} 

Cho phép xem làm thế nào chính có thể chuyển đổi giữa hai

public class Main { 
    public static void main(String[] args) throws Exception { 
      Employee emp = new Employee(); 
      ... set employee information 

      DBOperation dboper = null; 
      // declare your db operation object, not there is no instance 
      // associated with it 

      if(args[0].equals("use_rdbms")) { 
       dboper = new DBOperation_RDBMS(); 
       // here conditionally, i.e when first argument to program is 
       // use_rdbms, we instantiate RDBM implementation and associate 
       // with variable dboper, which delcared as DBOperation. 
       // this is where runtime binding of polymorphism kicks in 
       // JVM is allowing this assignment because DBOperation_RDBMS 
       // has a "is a" relationship with DBOperation. 
      } else if(args[0].equals("use_fs")) { 
       dboper = new DBOperation_FileSystem(); 
       // similarly here conditionally we assign a different instance. 
      } else { 
       throw new RuntimeException("Dont know which implemnation to use"); 
      } 

      dboper.addEmployee(emp); 
      // now dboper is refering to one of the implementation 
      // based on the if conditions above 
      // by this point JVM knows dboper variable is associated with 
      // 'a' implemenation, and it will call appropriate method    
    } 
} 

Bạn có thể sử dụng khái niệm đa hình ở nhiều nơi, một ví dụ praticle sẽ là: cho phép bạn đang viết hình ảnh decorer, và bạn cần phải hỗ trợ toàn bộ loạt các hình ảnh như vậy như jpg, tif, png, v.v. Vì vậy, ứng dụng của bạn sẽ định nghĩa một giao diện và làm việc trực tiếp trên đó. Và bạn sẽ có một số ràng buộc thời gian chạy của các triển khai khác nhau cho mỗi jpg, tif, pgn, v.v.

Một điều quan trọng khác là, nếu bạn đang sử dụng java, hầu hết thời gian bạn làm việc trên giao diện Danh sách có thể sử dụng ArrayList ngày hôm nay hoặc một số giao diện khác khi ứng dụng của bạn phát triển hoặc nhu cầu của nó thay đổi.

+0

tốt! thats chính xác những gì tôi gọi để trả lời của tôi ở trên. Nó giúp trong việc gọi điện năng động của các chức năng chính xác. ! –

0

Tôi đoán đôi khi các đối tượng được gọi tự động. Bạn không chắc liệu đối tượng đó có phải là hình tam giác, hình vuông, v.v ... trong một hình dạng cổ điển hay không. thí dụ.

Vì vậy, để lại tất cả những thứ như vậy, chúng ta chỉ cần gọi hàm của lớp dẫn xuất và giả sử một lớp năng động sẽ được gọi.

Bạn sẽ không quan tâm nếu đó là hình vuông, hình tam giác hoặc hình chữ nhật. Bạn chỉ quan tâm đến khu vực.Do đó phương thức getArea sẽ được gọi tùy thuộc vào đối tượng động được truyền.

16

Bạn đã bao giờ thêm hai số nguyên với + rồi sau đó thêm số nguyên vào số dấu phẩy động với +?

Bạn đã bao giờ đăng nhập x.toString() để giúp bạn gỡ lỗi một cái gì đó?

Tôi nghĩ bạn có thể đã đánh giá cao tính đa hình, chỉ cần không biết tên.

0

Một trong những lợi ích quan trọng nhất mà bạn nhận được từ các hoạt động đa hình là khả năng mở rộng. Bạn có thể sử dụng các thao tác tương tự và không thay đổi các giao diện và triển khai hiện có chỉ vì bạn phải đối mặt với sự cần thiết đối với một số nội dung mới.

Tất cả những gì chúng tôi muốn từ đa hình - đơn giản hóa quyết định thiết kế của chúng tôi và làm cho thiết kế của chúng tôi mở rộng và thanh lịch hơn. Bạn cũng nên chú ý đến Nguyên tắc đóng mở (http://en.wikipedia.org/wiki/Open/closed_principle) và đối với SOLID (http://en.wikipedia.org/wiki/Solid_%28Object_Oriented_Design%29) có thể giúp bạn hiểu các nguyên tắc chính của OO.

P.S. Tôi nghĩ bạn đang nói về "Đa hình năng động" (http://en.wikipedia.org/wiki/Dynamic_polymorphism), bởi vì có những thứ như "Đa hình tĩnh" (http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism).

5

Ưu điểm của đa hình là mã máy khách không cần quan tâm đến việc triển khai thực tế của phương thức. Hãy xem ví dụ sau. Ở đây CarBuilder không biết gì về ProduceCar() Một khi nó được đưa ra một danh sách các xe ô tô (CarsToProduceList) nó sẽ sản xuất tất cả những chiếc xe cần thiết cho phù hợp.

class CarBase 
{ 
    public virtual void ProduceCar() 
    { 
     Console.WriteLine("don't know how to produce"); 
    } 
} 

class CarToyota : CarBase 
{ 
    public override void ProduceCar() 
    { 
     Console.WriteLine("Producing Toyota Car "); 
    } 
} 

class CarBmw : CarBase 
{ 
    public override void ProduceCar() 
    { 
     Console.WriteLine("Producing Bmw Car"); 
    } 
} 

class CarUnknown : CarBase { } 

class CarBuilder 
{ 
    public List<CarBase> CarsToProduceList { get; set; } 

    public void ProduceCars() 
    { 
     if (null != CarsToProduceList) 
     { 
      foreach (CarBase car in CarsToProduceList) 
      { 
       car.ProduceCar();// doesn't know how to produce 
      } 
     } 

    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     CarBuilder carbuilder = new CarBuilder(); 
     carbuilder.CarsToProduceList = new List<CarBase>() { new CarBmw(), new CarToyota(), new CarUnknown() };    
     carbuilder.ProduceCars(); 
    } 
} 
0

Applications Tabbed

Một ứng dụng tốt với tôi là nút generic (cho tất cả các tab) trong một tab ứng dụng - ngay cả trình duyệt, chúng tôi đang sử dụng nó đang thực hiện Polymorphism như nó doesn' t biết tab chúng tôi đang sử dụng tại thời điểm biên dịch (trong mã nói cách khác là). Nó luôn được xác định tại thời gian chạy (ngay bây giờ! Khi chúng tôi đang sử dụng trình duyệt.)

Các vấn đề liên quan