2012-09-03 54 views
29

Tôi không thực sự chắc chắn điều gì sẽ đẹp hơn hoặc khi nào tôi thực sự sử dụng trong lớp trừu tượng và thuộc tính hoặc khi sử dụng thuộc tính không trừu tượng. Tôi sẽ cố gắng làm một ví dụ đơn giản. Giả sử tôi có điều này:Không chắc chắn khi nào nên sử dụng thuộc tính trừu tượng và khi không

abstract class Human 
{ 
    public GenderType Gender { get; set; } 
    public string Name { get; set; } 
    public Date Born { get; set; } 
    public bool IsNerd { get; set; } 

    abstract public void Speak(); 
    abstract public void Sleep(); 
    abstract public void AnoyingPeopleOnStackOverflow(); 
    //... so on 
} 

class Peter : Human 
{ 
    //Peter is special, he got a second name 
    //But thats all, everything else is the same as like on other humans 
    public string SecondName { get; set; } 

    //...override abstract stuff 
} 

Điều này có ổn không? Như tôi đã hiểu, tôi không phải sử dụng một thuộc tính trừu tượng nếu tôi không muốn ghi đè nó. Và trong tình huống này, nó sẽ là ok, chỉ cần các phương pháp như Speak, Sleep và như vậy sẽ được trừu tượng.

Bây giờ, nếu điều này là ok, khi nào hoặc tôi nên sử dụng thuộc tính trừu tượng?

+1

"Khi nào hoặc nên sử dụng thuộc tính trừu tượng" --- khi bạn muốn khẳng định rằng lớp con phải cung cấp phương pháp triển khai cụ thể – zerkms

+1

1) Nếu đây là Java, có thể sẽ không có vấn đề gì. Bạn có thể chỉ cần sử dụng một "giao diện". Đó chính là những gì bạn đang làm ở đây trong C#, phải không?2) cảm giác cá nhân của tôi là nếu nó cần phải là một phần của "hợp đồng", sau đó nó là thích hợp để tuyên bố nó trong lớp trừu tượng của bạn. Nói cách khác, tôi nghĩ rằng những gì bạn đã làm là hoàn toàn OK. IMHO ... – paulsm4

+1

@ paulsm4 bạn cũng có thể làm điều đó với C#. –

Trả lời

56

Sử dụng thuộc tính trừu tượng khi bạn không triển khai mặc định và khi lớp bắt nguồn phải triển khai.

Sử dụng thuộc tính ảo khi bạn có triển khai trong lớp cơ sở nhưng muốn cho phép ghi đè.

Sử dụng từ khóa override để ghi đè thành viên. Đánh dấu thành viên là sealed override nếu không được ghi đè lại.

Không đánh dấu thuộc tính là abstract hoặc virtual nếu bạn không muốn bị ghi đè.

Sử dụng từ khóa new để ẩn thành viên không trừu tượng, không phải ảo (điều này hiếm khi là ý tưởng hay).

How to: Define Abstract Properties

Tôi thấy rằng tính chất trừu tượng thường xảy ra trong một thiết kế mà ngụ ý rằng họ sẽ phải loại cụ thể logic và/hoặc tác dụng phụ. Về cơ bản bạn nói, "đây là một điểm dữ liệu mà tất cả các lớp con phải có, nhưng tôi không biết cách thực hiện nó". Tuy nhiên, thuộc tính có chứa một lượng lớn logic và/hoặc gây ra tác dụng phụ có thể không được mong muốn. Đây là một cân nhắc quan trọng, mặc dù không có cách cố định đúng/sai để làm điều đó.

Xem:

Cá nhân, tôi thấy rằng tôi sử dụng phương pháp trừu tượng thường xuyên nhưng tính chất trừu tượng hiếm.

4

Sử dụng tóm tắt khi tất cả các lớp con để triển khai phương pháp/thuộc tính. Nếu không có nhu cầu cho từng tiểu nhóm để thực hiện nó, thì đừng sử dụng nó.

Ví dụ: nếu không yêu cầu SecondName cho mỗi người, thì không cần phải tạo thuộc tính trừu tượng trong lớp cơ sở. Nếu mặt khác, mọi người đều cần một tên thứ hai, sau đó biến nó trở thành một tài sản trừu tượng.

Ví dụ về việc sử dụng đúng đắn về một tài sản trừu tượng:

public class Car 
{ 
    public abstract string Manufacturer { get; } 
} 

public class Odyssey : Car 
{ 
    public override string Manufacturer 
    { 
     get 
     { 
      return "Honda"; 
     } 
    } 
} 

public class Camry : Car 
{ 
    public override string Manufacturer 
    { 
     get 
     { 
      return "Toyota"; 
     } 
    } 
} 

Làm Maker trừu tượng là đúng vì mỗi xe có một nhà sản xuất và nhu cầu để có thể nói với người dùng sản xuất đó là.

1

Thuộc tính trừu tượng sẽ được sử dụng nơi bạn muốn lớp luôn hiển thị thuộc tính, nhưng tại đây bạn không thể ghim chặt sự thực hiện của thuộc tính đó - để cho phép lớp thừa kế làm như vậy.

Có một ví dụ here, trong đó lớp trừu tượng có tên Shape và hiển thị thuộc tính trừu tượng Area. Bạn không thể triển khai thuộc tính Area trong lớp cơ sở vì công thức cho khu vực sẽ thay đổi đối với từng loại hình dạng. Tất cả các hình dạng có một khu vực (một số loại), vì vậy tất cả các hình dạng nên phơi bày tài sản.

Bản thân việc triển khai của bạn có vẻ ổn. Đã cố gắng nghĩ về một ví dụ hợp lý về một tài sản trừu tượng cho một số Human, nhưng không thể nghĩ ra bất cứ điều gì hợp lý.

11

Thành viên trừu tượng chỉ đơn giản là thành viên ảo mà bạn phải ghi đè. Bạn sử dụng điều này cho một cái gì đó đã được thực hiện, nhưng không thể được thực hiện trong lớp cơ sở.

Nếu bạn muốn tạo một thuộc tính ảo và muốn rằng nó phải được ghi đè trong lớp thừa hưởng lớp của bạn, thì bạn sẽ biến nó thành thuộc tính trừu tượng.

Nếu bạn ví dụ có một lớp chăn nuôi, khả năng hít thở sẽ không thể tự xác định được chỉ từ những thông tin rằng đó là một con vật, nhưng nó là cái gì đó là khá quan trọng:

public abstract class Animal { 

    public abstract bool CanBreathe { get; } 

} 

Đối với một con cá và một con chó triển khai sẽ khác nhau:

public class Dog : Animal { 

    public override bool CanBreathe { get { return !IsUnderWater; } } 

} 

public class Fish : Animal { 

    public override bool CanBreathe { get { return IsUnderWater; } } 

} 
26

Tôi biết những gì tôi muốn họ làm, tôi không quan tâm họ làm thế nào: Giao diện.

Tôi biết những gì tôi muốn họ làm, tôi không quan tâm làm thế nào họ làm một số của nó, nhưng tôi đã ý tưởng vững chắc về cách họ sẽ (hoặc ít nhất là hầu hết trong số họ) làm bit khác: Tóm tắt lớp .

Tôi biết những gì tôi muốn họ làm, và làm thế nào hầu hết trong số họ sẽ làm điều đó: Lớp bê tông với các thành viên ảo.

Bạn có thể có các trường hợp khác, ví dụ: một lớp trừu tượng không có thành phần trừu tượng (bạn không thể có một thể hiện, nhưng nó cung cấp cái gì, nó cung cấp hoàn toàn), nhưng chúng hiếm hơn và thường xuất hiện bởi vì một hệ thống phân cấp cụ thể tự cung cấp một cách rõ ràng và rõ ràng vấn đề.

(Ngẫu nhiên, tôi sẽ không nghĩ về Peter như một loại Nhân loại, nhưng mỗi peter là một trường hợp của con người được gọi là Peter. Thật không công bằng khi chọn mã ví dụ theo cách này, nhưng khi bạn đang nghĩ về loại vấn đề này thì nó thích hợp hơn bình thường).

+3

+1 - Đồng ý, 'Peter' phải là một thể hiện của một phân lớp của' Human', ví dụ: 'HumansWithTwoNames' –

+2

@TimMedora Vâng, và tất cả chúng ta đều nghĩ về những cái tên xấu khi tạo mã ví dụ, và nó thường không quan trọng, nhưng đây là một câu hỏi mà nó quan trọng nhất. –

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