Thành phần và kế thừa có giống nhau không? Nếu tôi muốn triển khai mẫu thành phần, làm thế nào tôi có thể làm điều đó trong Java?
Thành phần và kế thừa có giống nhau không? Nếu tôi muốn triển khai mẫu thành phần, làm thế nào tôi có thể làm điều đó trong Java?
Câu trả lời:
Họ hoàn toàn khác nhau. Kế thừa là một mối quan hệ "là-một" . Thành phần là "có-a" .
Bạn thực hiện sáng tác bằng cách có một thể hiện của một lớp khác C
như một trường của lớp của bạn, thay vì mở rộng C
. Một ví dụ điển hình trong đó sáng tác sẽ tốt hơn nhiều so với kế thừa java.util.Stack
, hiện đang mở rộng java.util.Vector
. Điều này hiện được coi là một sai lầm. Một vectơ "KHÔNG-KHÔNG-a" ; bạn không được phép chèn và loại bỏ các yếu tố tùy ý. Nó nên là thành phần thay thế.
Thật không may, đã quá muộn để khắc phục lỗi thiết kế này, vì việc thay đổi hệ thống phân cấp thừa kế bây giờ sẽ phá vỡ tính tương thích với mã hiện có. Đã Stack
sử dụng thành phần thay vì kế thừa, nó luôn có thể được sửa đổi để sử dụng cấu trúc dữ liệu khác mà không vi phạm API .
Tôi đánh giá cao cuốn sách Josh Bloch của Java phiên bản 2 hiệu quả
Thiết kế hướng đối tượng tốt không phải là tự do mở rộng các lớp hiện có. Bản năng đầu tiên của bạn nên sáng tác thay thế.
Xem thêm:
Thành phần có nghĩa là HAS A
Kế thừaIS A
Example
: Xe có Động cơ và Xe là Ô tô.
Trong lập trình, điều này được thể hiện như sau:
class Engine {} // The Engine class.
class Automobile {} // Automobile class which is parent to Car class.
class Car extends Automobile { // Car is an Automobile, so Car class extends Automobile class.
private Engine engine; // Car has an Engine so, Car class has an instance of Engine class as its member.
}
:-/
type
lĩnh vực LoạiEnum
Làm thế nào thừa kế có thể nguy hiểm?
Hãy lấy một ví dụ
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1) Như rõ ràng trong đoạn mã trên, Class Y có khả năng khớp nối rất mạnh với lớp X. Nếu có bất kỳ thay đổi nào trong siêu lớp X, Y có thể bị hỏng đáng kể. Giả sử Trong lớp X trong tương lai thực hiện một phương thức hoạt động với chữ ký dưới đây
public int work(){
}
Thay đổi được thực hiện trong lớp X nhưng nó sẽ làm cho lớp Y không thể hoàn thành. Vì loại phụ thuộc này có thể lên đến bất kỳ cấp độ nào và nó có thể rất nguy hiểm. Mỗi khi siêu lớp có thể không có khả năng hiển thị đầy đủ để mã bên trong tất cả các lớp con và lớp con của nó có thể luôn chú ý đến những gì đang xảy ra trong siêu lớp mọi lúc. Vì vậy, chúng ta cần tránh khớp nối mạnh mẽ và không cần thiết này.
Làm thế nào để thành phần giải quyết vấn đề này?
Hãy xem bằng cách sửa đổi ví dụ tương tự
public class X{
public void do(){
}
}
Public Class Y{
X x = new X();
public void work(){
x.do();
}
}
Ở đây chúng ta đang tạo tham chiếu của lớp X trong lớp Y và gọi phương thức của lớp X bằng cách tạo một thể hiện của lớp X. Bây giờ tất cả các khớp nối mạnh mẽ đã biến mất. Hiện tại, siêu lớp và lớp con rất độc lập với nhau. Các lớp có thể tự do thực hiện các thay đổi gây nguy hiểm trong tình huống thừa kế.
2) Ưu điểm thứ hai rất tốt của bố cục ở chỗ Nó cung cấp tính linh hoạt khi gọi phương thức, ví dụ:
class X implements R
{}
class Y implements R
{}
public class Test{
R r;
}
Trong lớp Test sử dụng tham chiếu r tôi có thể gọi các phương thức của lớp X cũng như lớp Y. Sự linh hoạt này không bao giờ có trong thừa kế
3) Một lợi thế lớn khác: Kiểm tra đơn vị
public class X {
public void do(){
}
}
Public Class Y {
X x = new X();
public void work(){
x.do();
}
}
Trong ví dụ trên, nếu không biết trạng thái của x, nó có thể dễ dàng bị giả lập bằng cách sử dụng một số dữ liệu thử nghiệm và tất cả các phương pháp có thể được kiểm tra dễ dàng. Điều này hoàn toàn không thể xảy ra khi thừa kế vì bạn phụ thuộc rất nhiều vào siêu lớp để có được trạng thái và thực hiện bất kỳ phương thức nào.
4) Một lý do chính đáng khác tại sao chúng ta nên tránh kế thừa là Java không hỗ trợ nhiều kế thừa.
Hãy lấy một ví dụ để hiểu điều này:
Public class Transaction {
Banking b;
public static void main(String a[])
{
b = new Deposit();
if(b.deposit()){
b = new Credit();
c.credit();
}
}
}
Điều tốt để biết:
thành phần dễ dàng đạt được trong thời gian chạy trong khi kế thừa cung cấp các tính năng của nó tại thời gian biên dịch
thành phần còn được gọi là quan hệ và thừa kế HAS-A còn được gọi là quan hệ IS-A
Vì vậy, hãy tạo thói quen luôn thích sáng tác hơn thừa kế vì nhiều lý do trên.
Câu trả lời được đưa ra bởi @Michael Coleues là không chính xác (tôi xin lỗi; tôi không thể nhận xét trực tiếp) và có thể dẫn đến một số nhầm lẫn.
Triển khai giao diện là một hình thức thừa kế ... khi bạn triển khai một giao diện, bạn không chỉ kế thừa tất cả các hằng số, bạn đang cam kết đối tượng của bạn thuộc loại được chỉ định bởi giao diện; nó vẫn là một mối quan hệ " là-một ". Nếu một chiếc xe thực hiện Fillable , chiếc xe " is-a " Fillable và có thể được sử dụng trong mã của bạn bất cứ nơi nào bạn sẽ sử dụng Fillable .
Thành phần về cơ bản là khác với thừa kế. Khi bạn sử dụng bố cục, bạn (như các câu trả lời khác lưu ý) tạo mối quan hệ " có-có " giữa hai đối tượng, trái ngược với mối quan hệ " is-a " mà bạn thực hiện khi bạn sử dụng tính kế thừa .
Vì vậy, từ các ví dụ về xe hơi trong các câu hỏi khác, nếu tôi muốn nói rằng một chiếc xe " có bình xăng", tôi sẽ sử dụng bố cục, như sau:
public class Car {
private GasTank myCarsGasTank;
}
Hy vọng rằng sẽ xóa mọi hiểu lầm.
Kế thừa mang lại mối quan hệ IS-A . Thành phần mang lại mối quan hệ HAS-A . Mẫu chiến lược giải thích rằng Thành phần nên được sử dụng trong trường hợp có các họ thuật toán xác định một hành vi cụ thể.
Ví dụ cổ điển là lớp vịt thực hiện hành vi bay.
public interface Flyable{
public void fly();
}
public class Duck {
Flyable fly;
public Duck(){
fly = new BackwardFlying();
}
}
Vì vậy, chúng ta có thể có nhiều lớp thực hiện bay, ví dụ:
public class BackwardFlying implements Flyable{
public void fly(){
Systemout.println("Flies backward ");
}
}
public class FastFlying implements Flyable{
public void fly(){
Systemout.println("Flies 100 miles/sec");
}
}
Nếu được thừa kế, chúng ta sẽ có hai lớp chim khác nhau thực hiện chức năng bay đi bay lại. Vì vậy, kế thừa và thành phần là hoàn toàn khác nhau.
Bố cục giống như âm thanh - bạn tạo một đối tượng bằng cách cắm vào các phần.
EDIT phần còn lại của câu trả lời này là sai dựa trên tiền đề sau.
Điều này được thực hiện với Giao diện.
Ví dụ: sử dụng Car
ví dụ trên,
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
Vì vậy, với một vài thành phần lý thuyết tiêu chuẩn, bạn có thể xây dựng đối tượng của mình. Sau đó, công việc của bạn là điền vào cách thức House
bảo vệ người cư ngụ và cách Car
bảo vệ người cư ngụ.
Kế thừa giống như cách khác. Bạn bắt đầu với một đối tượng hoàn chỉnh (hoặc bán hoàn chỉnh) và bạn thay thế hoặc Ghi đè các bit khác nhau mà bạn muốn thay đổi.
Ví dụ, MotorVehicle
có thể đi kèm với một Fuelable
phương pháp và Drive
phương pháp. Bạn có thể rời khỏi phương pháp Nhiên liệu vì nó giống nhau khi đổ đầy xe máy và ô tô, nhưng bạn có thể ghi đè Drive
phương thức này vì Xe máy lái rất khác so với a Car
.
Với tính kế thừa, một số lớp đã được triển khai hoàn toàn và các lớp khác có các phương thức mà bạn buộc phải ghi đè. Với Thành phần không có gì được trao cho bạn. (nhưng bạn có thể Thực hiện các giao diện bằng cách gọi các phương thức trong các lớp khác nếu bạn tình cờ có thứ gì đó nằm xung quanh).
Thành phần được xem là linh hoạt hơn, bởi vì nếu bạn có một phương thức như iUsesFuel, bạn có thể có một phương thức ở một nơi khác (một lớp khác, một dự án khác) mà chỉ lo lắng về việc xử lý các vật thể có thể được cung cấp nhiên liệu, bất kể đó là xe hơi, thuyền, bếp, thịt nướng, v.v. Các giao diện bắt buộc các lớp nói rằng chúng thực hiện giao diện đó thực sự có các phương thức mà giao diện đó là tất cả. Ví dụ,
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
sau đó bạn có thể có một phương pháp ở nơi khác
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
Ví dụ kỳ lạ, nhưng nó cho thấy phương thức này không quan tâm đến những gì nó lấp đầy, bởi vì đối tượng thực hiện iUsesFuel
, nó có thể được lấp đầy. Kết thúc câu chuyện.
Nếu bạn đã sử dụng Kế thừa thay thế, bạn sẽ cần các FillHerUp
phương thức khác nhau để xử lý MotorVehicles
và Barbecues
, trừ khi bạn có một số đối tượng cơ bản "ObjectThatUsesFuel" khá kỳ lạ để kế thừa.
ThisCase
, không phải trong camelCase
. Do đó, tốt nhất là đặt tên cho các giao diện của bạn IDrivable
, v.v. Bạn có thể không cần "Tôi" nếu bạn tập hợp lại tất cả các giao diện của mình thành một gói chính xác.
Thành phần và kế thừa có giống nhau không?
Chúng không giống nhau.
Thành phần : Nó cho phép một nhóm các đối tượng phải được xử lý theo cùng một cách như một thể hiện của một đối tượng. Mục đích của hỗn hợp là "kết hợp" các đối tượng thành các cấu trúc cây để thể hiện hệ thống phân cấp toàn bộ
Kế thừa : Một lớp kế thừa các trường và phương thức từ tất cả các siêu lớp của nó, cho dù trực tiếp hay gián tiếp. Một lớp con có thể ghi đè các phương thức mà nó kế thừa hoặc nó có thể ẩn các trường hoặc các phương thức mà nó kế thừa.
Nếu tôi muốn triển khai mẫu thành phần, làm thế nào tôi có thể làm điều đó trong Java?
Bài viết Wikipedia là đủ tốt để thực hiện mô hình tổng hợp trong java.
Những người tham gia chính:
Thành phần :
Lá :
Hợp chất :
Ví dụ mã để hiểu mẫu tổng hợp :
import java.util.List;
import java.util.ArrayList;
interface Part{
public double getPrice();
public String getName();
}
class Engine implements Part{
String name;
double price;
public Engine(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Trunk implements Part{
String name;
double price;
public Trunk(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Body implements Part{
String name;
double price;
public Body(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Car implements Part{
List<Part> parts;
String name;
public Car(String name){
this.name = name;
parts = new ArrayList<Part>();
}
public void addPart(Part part){
parts.add(part);
}
public String getName(){
return name;
}
public String getPartNames(){
StringBuilder sb = new StringBuilder();
for ( Part part: parts){
sb.append(part.getName()).append(" ");
}
return sb.toString();
}
public double getPrice(){
double price = 0;
for ( Part part: parts){
price += part.getPrice();
}
return price;
}
}
public class CompositeDemo{
public static void main(String args[]){
Part engine = new Engine("DiselEngine",15000);
Part trunk = new Trunk("Trunk",10000);
Part body = new Body("Body",12000);
Car car = new Car("Innova");
car.addPart(engine);
car.addPart(trunk);
car.addPart(body);
double price = car.getPrice();
System.out.println("Car name:"+car.getName());
System.out.println("Car parts:"+car.getPartNames());
System.out.println("Car price:"+car.getPrice());
}
}
đầu ra:
Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0
Giải trình:
Tham khảo câu hỏi dưới đây để biết ưu và nhược điểm của thành phần và kế thừa.
Thành phần là nơi một cái gì đó được tạo thành từ các phần riêng biệt và nó có mối quan hệ chặt chẽ với các phần đó. Nếu phần chính chết đi, những người khác cũng không thể có một cuộc sống của riêng họ. Một ví dụ thô là cơ thể con người. Lấy ra trái tim và tất cả các phần khác chết đi.
Kế thừa là nơi bạn chỉ cần lấy một cái gì đó đã tồn tại và sử dụng nó. Không có mối quan hệ mạnh mẽ. Một người có thể thừa kế gia sản của cha mình nhưng anh ta có thể làm mà không cần nó.
Tôi không biết Java vì vậy tôi không thể cung cấp một ví dụ nhưng tôi có thể cung cấp giải thích về các khái niệm.
Kế thừa giữa hai lớp, trong đó một lớp mở rộng một lớp khác thiết lập mối quan hệ " IS A ".
Thành phần ở đầu bên kia chứa một thể hiện của một lớp khác trong lớp của bạn thiết lập mối quan hệ " Có A ". Thành phần trong java là hữu ích vì về mặt kỹ thuật tạo điều kiện cho nhiều kế thừa.
Trong tập hợp từ đơn giản có nghĩa là có một mối quan hệ ..
Thành phần là một trường hợp đặc biệt của tập hợp . Theo một cách cụ thể hơn, một tập hợp hạn chế được gọi là thành phần. Khi một đối tượng chứa đối tượng khác, nếu đối tượng được chứa không thể tồn tại mà không có sự tồn tại của đối tượng container, thì nó được gọi là thành phần. Ví dụ: Một lớp chứa sinh viên. Một học sinh không thể tồn tại mà không có một lớp học. Có thành phần tồn tại giữa lớp và sinh viên.
Tại sao sử dụng Uẩn
Mã tái sử dụng
Khi sử dụng tổng hợp
Tái sử dụng mã cũng đạt được tốt nhất bằng cách tổng hợp khi không có tàu quan hệ
Di sản
Thừa kế là một mối quan hệ cha mẹ Con cái Kế thừa là một mối quan hệ
Kế thừa trong java là một cơ chế trong đó một đối tượng có được tất cả các thuộc tính và hành vi của đối tượng cha.
Sử dụng tính kế thừa trong khả năng sử dụng lại mã Java 1. 2 Thêm tính năng bổ sung trong lớp con cũng như ghi đè phương thức (để có thể đạt được tính đa hình thời gian chạy).
Mặc dù cả Kế thừa và Thành phần đều cung cấp khả năng sử dụng lại mã, nhưng điểm khác biệt chính giữa Thành phần và Kế thừa trong Java là Thành phần cho phép sử dụng lại mã mà không cần mở rộng mã nhưng đối với Kế thừa, bạn phải mở rộng lớp cho bất kỳ việc sử dụng lại mã hoặc chức năng nào. Một điểm khác biệt xuất phát từ thực tế này là bằng cách sử dụng Thành phần, bạn có thể sử dụng lại mã cho lớp cuối cùng không thể mở rộng nhưng Kế thừa không thể sử dụng lại mã trong các trường hợp như vậy. Ngoài ra, bằng cách sử dụng Thành phần, bạn có thể sử dụng lại mã từ nhiều lớp vì chúng được khai báo là biến thành viên, nhưng với Kế thừa, bạn có thể sử dụng lại mẫu mã chỉ một lớp vì trong Java bạn chỉ có thể mở rộng một lớp, vì nhiều Kế thừa không được hỗ trợ trong Java . Bạn có thể làm điều này trong C ++ vì có một lớp có thể mở rộng nhiều hơn một lớp. BTW, bạn nên luôn luônthích Sáng tác hơn Kế thừa trong Java , không chỉ tôi mà ngay cả Joshua Bloch cũng đã gợi ý trong cuốn sách của mình
Tôi nghĩ ví dụ này giải thích rõ ràng sự khác biệt giữa thừa kế và thành phần .
Trong exmple này, vấn đề được giải quyết bằng cách sử dụng kế thừa và thành phần. Tác giả chú ý đến thực tế rằng; trong kế thừa , một thay đổi trong siêu lớp có thể gây ra vấn đề trong lớp dẫn xuất, kế thừa nó.
Ở đó bạn cũng có thể thấy sự khác biệt về đại diện khi bạn sử dụng UML cho kế thừa hoặc thành phần.
Kế thừa Vs Thành phần.
Kế thừa và thành phần cả hai được sử dụng để tái sử dụng và mở rộng hành vi của lớp.
Kế thừa chủ yếu sử dụng trong mô hình lập trình thuật toán gia đình như kiểu quan hệ IS-A có nghĩa là loại đối tượng tương tự. Thí dụ.
Những thứ này thuộc về gia đình Car.
Thành phần đại diện cho mối quan hệ HAS-A Type. Nó cho thấy khả năng của một đối tượng như Duster có Five Gears, Safari có bốn Gears, vv Bất cứ khi nào chúng ta cần mở rộng khả năng của một lớp hiện có thì hãy sử dụng thành phần. Ví dụ chúng ta cần thêm một thiết bị nữa trong đối tượng Duster sau đó chúng ta phải tạo thêm một đối tượng bánh răng và kết hợp nó với đối tượng khăn lau.
Chúng ta không nên thực hiện các thay đổi trong lớp cơ sở cho đến khi / trừ khi tất cả các lớp dẫn xuất cần các chức năng đó. Đối với kịch bản này, chúng ta nên sử dụng Thành phần.
lớp A Xuất phát từ lớp B
Lớp A Xuất phát từ lớp C
Lớp A Xuất phát từ lớp D.
Khi chúng ta thêm bất kỳ chức năng nào trong lớp A thì nó có sẵn cho tất cả các lớp con ngay cả khi Lớp C và D không yêu cầu các chức năng đó. Đối với kịch bản này, chúng ta cần tạo một lớp riêng cho các chức năng đó và kết hợp nó với lớp được yêu cầu ( đây là lớp B).
Dưới đây là ví dụ:
// This is a base class
public abstract class Car
{
//Define prototype
public abstract void color();
public void Gear() {
Console.WriteLine("Car has a four Gear");
}
}
// Here is the use of inheritence
// This Desire class have four gears.
// But we need to add one more gear that is Neutral gear.
public class Desire : Car
{
Neutral obj = null;
public Desire()
{
// Here we are incorporating neutral gear(It is the use of composition).
// Now this class would have five gear.
obj = new Neutral();
obj.NeutralGear();
}
public override void color()
{
Console.WriteLine("This is a white color car");
}
}
// This Safari class have four gears and it is not required the neutral
// gear and hence we don't need to compose here.
public class Safari :Car{
public Safari()
{ }
public override void color()
{
Console.WriteLine("This is a red color car");
}
}
// This class represents the neutral gear and it would be used as a composition.
public class Neutral {
public void NeutralGear() {
Console.WriteLine("This is a Neutral Gear");
}
}
Thành phần có nghĩa là tạo một đối tượng cho một lớp có quan hệ với lớp cụ thể đó. Giả sử Sinh viên có quan hệ với Tài khoản;
Một thừa kế là, đây là lớp trước với tính năng mở rộng. Điều đó có nghĩa là lớp mới này là lớp Cũ với một số tính năng mở rộng. Giả sử sinh viên là sinh viên nhưng tất cả sinh viên là con người. Vì vậy, có một mối quan hệ với sinh viên và con người. Đây là sự kế thừa.
Không, cả hai đều khác nhau. Thành phần tuân theo mối quan hệ "HAS-A" và kế thừa theo mối quan hệ "IS-A". Ví dụ tốt nhất cho thành phần là mô hình chiến lược.
Kế thừa có nghĩa là sử dụng lại chức năng hoàn chỉnh của một lớp, Ở đây, lớp của tôi phải sử dụng tất cả các phương thức của siêu lớp và lớp của tôi sẽ được kết hợp chính xác với siêu lớp và mã sẽ được sao chép trong cả hai lớp trong trường hợp kế thừa.
Nhưng chúng ta có thể khắc phục từ tất cả những vấn đề này khi chúng ta sử dụng bố cục để nói chuyện với một lớp khác. thành phần đang khai báo một thuộc tính của một lớp khác vào lớp của tôi mà chúng ta muốn nói chuyện. và chức năng nào chúng ta muốn từ lớp đó chúng ta có thể nhận được bằng cách sử dụng thuộc tính đó.