GoF 2 alapelv
From Wikipedia, the free encyclopedia
Remove ads
Az 1994-ben a Design Patterns: Elements of Reusable Object-Oriented Software (Programtervezési minták, Újrahasznosítható elemek objektumközpontú programokhoz) c. könyvben jelent meg. A GoF 2 eredeti angol megfogalmazása: „Favor object composition over class inheritance”,[1] azaz „Használj objektum-összetételt öröklés helyett, ha csak lehet”. Az objektum-összetétel az öröklődés (inheritance) alternatívája. Az öröklődést szokás IS-A kapcsolatnak (the dog is a vertebrate / a kutya egy gerinces), míg az objektum összetételt HAS-A kapcsolatnak (the dog has a spine / a kutyának van egy gerince) nevezni. Itt az új szolgáltatások úgy jönnek létre, hogy kisebb részekből építünk fel objektumokat, hogy több szolgáltatással rendelkezzenek. Az objektum-összetételnél az összeépített objektumoknak jól meghatározott interfésszel kell rendelkezniük. Az ilyen újrafelhasználást feketedobozos újrafelhasználásnak nevezzük, mert az objektumok belső részei láthatatlanok. Az objektumok „fekete dobozokként” jelennek meg. Az alosztályokon keresztül történő újrafelhasználást fehérdobozos újrafelhasználásnak nevezzük. A „fehér doboz” itt a láthatóságra utal: az öröklődéssel az alosztályok gyakran látják a szülőosztály belső részeit. A GoF 2 felhasználására remek példa a stratégia programtervezési minta.
Ezt a szócikket össze kellene dolgozni az Öröklődés helyett objektum-összetétel szócikkel. |
Az alapelv előnyeit, hátrányait, valamint további információkat megtalálhatja az Öröklődés helyett objektum-összetétel oldalon.
Remove ads
Programozási példák
Példa objektum összetételre (GoF 2)
C#
public interface HogyanRepül
{
void repül();
}
public class LassanRepül : HogyanRepül
{
public void repül()
{
Console.WriteLine("Nagyon lassan repül . . .");
}
}
public class GyorsanRepül : HogyanRepül
{
public void repül()
{
Console.WriteLine("Gyorsan repül...");
}
}
public class Kacsa
{
protected HogyanRepül repülésTípus; // HAS-A kapcsolat
public void repül()
{
// a repülést egy a HogyanRepül interfacet implementáló osztály hajtja végre
repülésTípusa.repül();
}
public HogyanRepül getRepülésTípusa()
{
return repülésTípusa;
}
// Az objektum összetétel egyik legnagyobb előnye, hogy
// futási időben megváltoztatható
public void setHogyanRepül(HogyanRepül repülésTípusa)
{
this.repülésTípusa = repülésTípusa;
}
public void úszik()
{
Console.WriteLine("Úszik a vízen");
}
public void hápog()
{
Console.WriteLine("háp háp");
}
// Az alapértelmezett konstruktorba érdemes beállítani egy
// alapértelmezett osztályt ami implementálja a HogyanRepül interfacet
public Kacsa()
{
repülésTípusa = LassanRepül;
}
// De létrehozhatunk egy külön konstruktort aminek
// az egyik paramétereként megadhatjuk azt.
public Kacsa(HogyanRepül repülésTípusa)
{
this.repülésTípusa = repülésTípusa;
}
}
public class KülönlegesGyorsanRepülőKacsa : Kacsa
{
// Minden tulajdonsága megegyezik az ősével, kivéve a repülés típusa
public KülönlegesGyorsanRepülőKacsa()
{
this.repülésTípusa = new GyorsanRepül();
}
}
Java
public interface HogyanRepül{
void repül();
}
public class LassanRepül implements HogyanRepül{
@Override
public void repül() {
System.out.println("Nagyon lassan repül . . .");
}
}
public class GyorsanRepül implements HogyanRepül{
@Override
public void repül() {
System.out.println("Gyorsan repül...");
}
}
public class Kacsa {
HogyanRepül repülésTípusa; // HAS-A kapcsolat
public void repül(){
// a repülést egy, a HogyanRepül interfacet implementáló osztály hajtja végre
repülésTípusa.repül();
}
public HogyanRepül getRepülésTípusa(){
return repülésTípusa;
}
// Az objektum összetétel egyik legnagyobb előnye, hogy
// futási időben megváltoztatható
public void setHogyanRepül(HogyanRepül repülésTípusa){
this.repülésTípusa = repülésTípusa;
}
public void úszik(){
System.out.println("Úszik a vízen");
}
public void hápog(){
System.out.println("háp háp");
}
// Az alapértelmezett konstruktorba érdemes beállítani egy
// alapértelmezett osztályt ami implementálja a HogyanRepül interfacet
public Kacsa(){
repülésTípusa = LassanRepül;
}
// De létrehozhatunk egy külön konstruktort aminek
// az egyik paramétereként megadhatjuk azt.
public Kacsa(HogyanRepül repülésTípusa){
this.repülésTípusa = repülésTípusa;
}
}
public class KülönlegesGyorsanRepülőKacsa extends Kacsa{
// Minden tulajdonsága megegyezik az ősével, kivéve a repülés típusa
public KülönlegesGyorsanRepülőKacsa(){
this.repülésTípusa = new GyorsanRepül();
}
}
Példa öröklésre (GoF 2 ellenpélda)
C#
public class Kacsa
{
public void hápog()
{
Console.WriteLine("háp háp");
}
public void úszik()
{
Console.WriteLine("úszik a vízen");
}
public void repül()
{
Console.WriteLine("Nagyon lassan repül . . .");
}
}
// Szeretnék egy gyorsan repülő kacsa osztályt létrehozni,
// aminek az összes egyéb tulajdonsága megegyezik a szülőével
public class GyorsKacsa : Kacsa
{
// Ez nem jött be...
// Megöröklöm a szülő osztály repül metódusát
}
//Próbáljuk meg máshogyan
public class KülönlegesGyorsKacsa
{
public void hápog()
{
Console.WriteLine("háp háp");
}
public void úszik()
{
Console.WriteLine("úszik a vízen");
}
// Láthatjuk, hogy emiatt az apró változtatás miatt, kódismétlésre volt szükségünk
// ami egy 100-200 vagy több soros osztálynál már komoly probléma
// Persze megtehetnénk, hogy kiemeljük a Kacsa osztályból azokat a metódusokat,
// amik megegyeznek, de ez hosszú távon nem nyújt megoldást.
// Mi van például akkor ha a következő kacsa típusunk úszik metódusa különbözik?
public void repül()
{
Console.WriteLine("Gyorsan repül...");
}
}
Java
public class Kacsa{
public void hápog(){
System.out.println("háp háp");
}
public void úszik(){
System.out.println("úszik a vízen");
}
public void repül(){
System.out.println("Nagyon lassan repül . . .");
}
}
// Szeretnék egy gyorsan repülő kacsa osztályt létrehozni,
// aminek az összes egyéb tulajdonsága megegyezik a szülőével
public class GyorsKacsa extends Kacsa{
// Ez nem jött be...
// Megöröklöm a szülő osztály repül metódusát
}
//Próbáljuk meg máshogyan
public class KülönlegesGyorsKacsa{
public void hápog() {
System.out.println("háp háp");
}
public void úszik(){
System.out.println("úszik a vízen");
}
// Láthatjuk, hogy emiatt az apró változtatás miatt, kódismétlésre volt szükségünk
// ami egy 100-200 vagy több soros osztálynál már komoly probléma
// Persze megtehetnénk, hogy kiemeljük a Kacsa osztályból azokat a metódusokat,
// amik megegyeznek, de ez hosszú távon nem nyújt megoldást.
// Mi van például akkor ha a következő kacsa típusunk úszik metódusa különbözik?
public void repül(){
System.out.println("Gyorsan repül...");
}
}
Remove ads
Kapcsolódó szócikkek
Jegyzetek
Források
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads