質問
構成と継承は同じですか?構成パターンを実装したい場合、Javaでそれを行うにはどうすればよいですか?
解決
彼らは絶対に異なっています。継承は次のとおりです 「is-a」 関係。構成はaです "があります".
あなたは別のクラスのインスタンスを持つことによって作曲を行います C
クラスのフィールドとして、拡張する代わりに C
. 。構成が相続よりもはるかに優れていた良い例 java.util.Stack
, 、現在拡張されています java.util.Vector
. 。これは現在、失態と見なされています。スタック 「is-not-a」 ベクター;要素を任意に挿入および削除することを許可されないでください。代わりに構成だったはずです。
残念ながら、継承階層を変更すると既存のコードとの互換性が破壊されるため、この設計上の間違いを是正するには遅すぎます。 持っていました Stack
継承の代わりに使用されている組成は、APIに違反することなく別のデータ構造を使用するように常に変更できます.
ジョシュブロッホの本を強くお勧めします 効果的なJava第2版
- 項目16:継承に対する構成を好む
- 項目17:継承のための設計と文書、またはそれを禁止する
優れたオブジェクト指向設計は、既存のクラスを自由に拡張することではありません。あなたの最初の本能は、代わりに作曲することです。
参照:
他のヒント
構成は意味があります HAS A
継承手段 IS A
Example
: : 車 があります エンジンと車 aです 自動車
プログラミングでは、これは次のように表されます。
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.
}
どのように継承が危険になる可能性がありますか?
例を見てみましょう
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1)上記のコードではクリアなように、クラスYはクラスXと非常に強力な結合を持っています。スーパークラスXに変化がある場合、Yは劇的に壊れる可能性があります。将来のクラスXが以下の署名を使用してメソッド作業を実装するとします
public int work(){
}
ChangeはクラスXで行われますが、クラスYが補償できなくなります。したがって、この種の依存関係はあらゆるレベルに達する可能性があり、非常に危険な場合があります。スーパークラスがそのすべてのサブクラス内のコードを完全に視認性がない場合があり、サブクラスは常にスーパークラスで何が起こっているかに気づき続ける可能性があります。したがって、この強力で不必要な結合を避ける必要があります。
構成はこの問題をどのように解決しますか?
同じ例を改訂することで見てみましょう
public class X{
public void do(){
}
}
Public Class Y{
X x = new X();
public void work(){
x.do();
}
}
ここでは、YクラスのXクラスの参照を作成し、Xクラスのインスタンスを作成することによりXクラスの方法を呼び出します。今、その強力なカップリングはすべてなくなりました。スーパークラスとサブクラスは、現在、互いに非常に独立しています。クラスは、相続状況で危険な変更を自由に行うことができます。
2)たとえば、次のように、メソッドを呼び出すメソッドを提供するという点で、構成の2番目の非常に良い利点があります。
class X implements R
{}
class Y implements R
{}
public class Test{
R r;
}
Rリファレンスを使用したテストクラスでは、XクラスとYクラスのメソッドを呼び出すことができます。この柔軟性は、継承には決してありませんでした
3)もう1つの大きな利点:ユニットテスト
public class X {
public void do(){
}
}
Public Class Y {
X x = new X();
public void work(){
x.do();
}
}
上記の例では、Xインスタンスの状態が不明な場合、いくつかのテストデータを使用して簡単にモックアップでき、すべてのメソッドを簡単にテストできます。インスタンスの状態を取得して任意の方法を実行するためにスーパークラスに大きく依存していたため、これは継承ではまったく不可能でした。
4)継承を避けるべきもう1つの正当な理由は、Javaが多発性継承をサポートしていないことです。
これを理解するために例を取りましょう:
Public class Transaction {
Banking b;
public static void main(String a[])
{
b = new Deposit();
if(b.deposit()){
b = new Credit();
c.credit();
}
}
}
知っておくといい:
継承はコンパイル時にその機能を提供しながら、実行時に簡単に実現できます
構成はHAS-A関係と継承としても知られています。
したがって、さまざまな理由で、常に相続よりも構成を好む習慣にしてください。
@michael Rodriguesによって与えられた答えは正しくありません(謝罪します。直接コメントすることはできません)。混乱につながる可能性があります。
インターフェイスの実装 継承の形式です...インターフェイスを実装すると、すべての定数を継承するだけでなく、インターフェイスで指定されたタイプのオブジェクトをコミットしています。それはまだです」is-a「関係。車が実装されている場合 充填可能, 、車」is-a" 充填可能, 、そしてあなたが使用するところならどこでもあなたのコードで使用することができます 充填可能.
構成は継承と根本的に異なります。 構成を使用するとき、あなたは(他の回答のように)「)を作る「があります「2つのオブジェクト間の関係とは対照的に」is-a「継承を使用するときに行う関係.
だから、他の質問の車の例から、私が車だと言いたいなら」があります「ガソリンタンク、次のように構成を使用します。
public class Car {
private GasTank myCarsGasTank;
}
うまくいけば、それが誤解を解消することを願っています。
継承 引き出します is-a 関係。 構成 引き出します HAS-A関係。戦略パターンは、特定の動作を定義するアルゴリズムのファミリーがある場合に構成を使用する必要があることを説明しています。
古典的な例は、飛行行動を実装するアヒルのクラスのものです。
public interface Flyable{
public void fly();
}
public class Duck {
Flyable fly;
public Duck(){
fly = new BackwardFlying();
}
}
したがって、飛行を実装する複数のクラスを作成できます。
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");
}
}
継承のためにあれば、ハエ機能を何度も繰り返し実装する2つの異なるクラスの鳥があります。したがって、継承と構成は完全に異なります。
構成は聞こえるとおりです - あなたは部分を差し込むことでオブジェクトを作成します。
編集 この答えの残りは、次の前提に誤って基づいています。
これはインターフェイスで達成されます。
たとえば、を使用して Car
上記の例、
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
したがって、いくつかの標準的な理論的コンポーネントを使用すると、オブジェクトを構築できます。それから、どのように埋めるのはあなたの仕事です House
居住者を保護し、どのようにaを保護します Car
居住者を保護します。
継承は逆の方法に似ています。完全な(または半完全な)オブジェクトから始めて、変更するさまざまなビットを交換またはオーバーライドします。
例えば、 MotorVehicle
aが付属するかもしれません Fuelable
方法と Drive
方法。バイクと車を満たすのと同じであるため、燃料方法を残すことができますが、オーバーライドすることができます Drive
方法は、バイクがaに対して非常に異なって駆動するためです Car
.
継承を使用すると、一部のクラスはすでに完全に実装されており、他のクラスにはオーバーライドを余儀なくされる方法があります。構成では、あなたに何も与えられていません。 (ただし、他のクラスでメソッドを呼び出して、何かが横たわっている場合は、インターフェイスを実装できます)。
構成はより柔軟であると見なされます。なぜなら、iUSESFuelなどの方法がある場合、車であるかどうかに関係なく、燃料を補給できるオブジェクトに対処することを心配する方法(別のクラス、別のプロジェクト)を手に入れることができるため、ボート、ストーブ、バーベキューなど。インターフェイスは、インターフェイスに実際にそのインターフェイスがすべての方法を持っていることを実装するというクラスを義務付けています。例えば、
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
その後、他の場所にメソッドを作成できます
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
奇妙な例ですが、オブジェクトが実装されているため、この方法はそれが何を満たしているのか気にしないことを示しています iUsesFuel
, 、それは満たすことができます。話の終わり。
代わりに継承を使用した場合、異なる必要があります FillHerUp
対処する方法 MotorVehicles
と Barbecues
, 、あなたが継承するためにいくつかのかなり奇妙な「Objectthatusesfuel」ベースオブジェクトを持っていない限り。
構成と継承は同じですか?
彼らは同じではありません。
構成 :オブジェクトのグループを、オブジェクトの単一インスタンスと同じ方法で扱う必要があります。複合材料の意図は、オブジェクトをツリー構造に「構成」することです。 部分的な階層を表します
継承: :クラスは、直接または間接であろうと、すべてのスーパークラスからフィールドとメソッドを継承します。サブクラスは、継承する方法をオーバーライドしたり、継承するフィールドや方法を隠すことができます。
構成パターンを実装したい場合、Javaでそれを行うにはどうすればよいですか?
ウィキペディア 記事は、Javaに複合パターンを実装するのに十分です。
重要な参加者:
成分:
- 複合コンポーネントを含むすべてのコンポーネントの抽象化です
- のオブジェクトのインターフェイスを宣言します 構成
葉:
- の葉のオブジェクトを表します 構成
- すべてを実装します 成分 方法
複合:
- 複合コンポーネント(子供を持つコンポーネント)を表す
- 子供を操作する方法を実装します
- 一般的にそれらを子供に委任することにより、すべてのコンポーネント方法を実装します
理解するコード例 複合 パターン:
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());
}
}
出力:
Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0
説明:
- 部 葉です
- 車 多くの部品が含まれています
- 違う 部品 車の車が車に追加されました
- の価格 車 =合計(それぞれの価格 部 )
構成と相続の長所と短所については、以下の質問を参照してください。
別の例として、車のクラスを考慮してください。これは組成の適切な使用であり、車はエンジン、トランスミッション、タイヤ、シートなどを「」にします。これらのクラスのいずれも拡張しません。
単純な言葉では、集約手段には関係があります。
構成は集約の特別なケースです. 。より具体的な方法で、制限された集約は組成と呼ばれます。オブジェクトに他のオブジェクトが含まれている場合、コンテナオブジェクトの存在なしに含まれるオブジェクトが存在できない場合、構成と呼ばれます。例:クラスには学生が含まれています。学生はクラスなしでは存在できません。クラスと学生の間には構成が存在します。
なぜ集約を使用するのか
コードの再利用性
集約を使用する場合
コードの再利用は、関係船がない場合に集約によっても最適に達成されます
継承
継承は親子関係です継承は関係です
Javaの継承は、1つのオブジェクトが親オブジェクトのすべての特性と動作を取得するメカニズムです。
Java 1コードの再利用性で継承を使用します。 2子どものクラスに特徴を追加し、メソッドオーバーライド(ランタイムの多型を達成できるように)を追加します。
構成は、何かが異なる部分で構成されている場所であり、それらの部分と強い関係を持っています。メインパートが死んだ場合、他の部分も死んだ場合、彼らは自分の生活をすることができません。大まかな例は人体です。心を取り出して、他のすべての部分が死にます。
継承は、すでに存在するものを取り、それを使用するだけです。強い関係はありません。人は父親の財産を継承することができますが、彼はそれなしで行うことができます。
Javaがわからないので、例を提供することはできませんが、概念の説明を提供できます。
継承 1つのクラスが別のクラスを拡張する2つのクラスの間で確立する」aです" 関係。
構成 もう一方の端には、クラスの別のクラスのインスタンスが含まれています」があります" 関係。 構成 Javaでは、技術的に複数の継承を促進するため、Javaは有用です。
継承と構成の両方がコードの再生可能性を提供しますが、Javaの構成と継承の主な違いは、構成によりコードを拡張せずに再利用できることですが、継承のためには、コードまたは機能の再利用のためにクラスを拡張する必要があります。この事実に由来するもう1つの違いは、構成を使用することで、拡張できないが、継承がそのような場合にコードを再利用できない最終クラスのコードを再利用できることです。また、構成を使用することで、メンバー変数として宣言されているため、多くのクラスからコードを再利用できますが、継承を使用すると、Javaでは1つのクラスしか拡張できないため、1つのクラスのみを再利用できます。 。 1つのクラスが複数のクラスを拡張できるため、C ++でこれを行うことができます。ところで、あなたはいつもすべきです Javaの継承よりも構成を好む, 、それは私だけでなく、さえ ジョシュア・ブロッホ 彼の本で提案しています
この例は、間の違いをはっきりと説明していると思います 継承 と 構成.
この例では、問題は継承と構成を使用して解決されます。著者は、その事実に注意を払っています。の 継承, 、スーパークラスの変化は、派生したクラスに問題を引き起こす可能性があり、それを継承します。
また、継承または構成にUMLを使用する場合、表現の違いを確認できます。
http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition-これは、それがまったくゆっくりです
継承と構成。
継承と構成は両方とも、クラスの動作の再利用性と拡張に使用されます。
継承は、主にIS-A関係タイプなどのファミリアルゴリズムプログラミングモデルで使用します。これは、同様の種類のオブジェクトを意味します。例。
- ダスターは車です
- サファリは車です
これらは車の家族に属します。
構成はhas-a関係タイプを表します。ダスターには5つのギア、サファリには4つのギアなどがあるなど、オブジェクトの能力が表示されます。例 ダスターオブジェクトにもう1つのギアを追加する必要があります。その後、もう1つのギアオブジェクトを作成し、ダスターオブジェクトに作成する必要があります。
すべての派生クラスがそれらの機能を必要としていないまで//ない限り、ベースクラスで変更を行うべきではありません。
クラスbによって導出されたクラスA
クラスcによって導出されたクラスA c
クラスDによって派生したクラスA
クラスAに機能を追加すると、クラスCとDがそれらの機能を必要としない場合でも、すべてのサブクラスが利用できます。このシナリオでは、それらの機能のために個別のクラスを作成し、必要なクラスに作成する必要があります(これがクラスb)です。
以下は例です:
// 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");
}
}
構成とは、その特定のクラスと関係のあるクラスにオブジェクトを作成することを意味します。学生がアカウントと関係があると仮定します。
継承は、これは拡張機能を備えた以前のクラスです。つまり、この新しいクラスは、いくつかの拡張機能を備えた古いクラスです。学生が学生であると仮定しますが、すべての学生は人間です。したがって、学生と人間との関係があります。これは継承です。
いいえ、どちらも違います。構成は「has-a」の関係に続き、継承は「is-a」関係に続きます。構成の最良の例は、戦略的パターンでした。
継承とは、クラスの完全な機能を再利用することを意味します。ここでは、私のクラスはスーパークラスのすべての方法を使用する必要があり、クラスはスーパークラスと適切に結合され、コードは継承の場合に両方のクラスで複製されます。
ただし、構成を使用して別のクラスと話すときに、これらすべての問題を克服できます。作曲とは、私たちが話したい私のクラスに別のクラスの属性を宣言しています。そして、その属性を使用することで得ることができるそのクラスから私たちが望む機能。