Giriş
Composition UML terminolojisinde parent child (parça bütün) ilişkisine sahip ve birbirinden ayrılamaz parçalar anlamına gelir.
Composition UML terminolojisinde parent child (parça bütün) ilişkisine sahip ve birbirinden ayrılamaz parçalar anlamına gelir.
Ancak bu yazıdaki Composition kelimesinden kasıt bu değil. Yani UML terminolojisi ile konuşulmuyor. UML ile konuşuyor olsaydık sanırım başlık "Association over Inheritance" olmalıydı. Zaten Composition tanımına bakınca nüanslara takılmayın deniliyor. Kısaca kasıt bir başka sınıfı Field (Üye Alan) olarak kullanmak
Composition: when a Field’s type is a class, the field will hold a reference to another object, thus creating an association relationship between them. Without getting into the nuances of the difference between simple association, aggregation, and composition, let’s intuitively define composition as when the class uses another object to provide some or all of its functionality.
Kalıtım Ne Zaman Kötü
Bazen nesnenin yaşam döngüsü içinde kendiliğinden değişecek şeyler, bileşim yapılacağına kalıtım haline getiriliyor.
Örnek
Elimizde şöyle bir kod olsun. Burada herkese Person nesnesinden kalıtıyor. Student mezun olup Teacher olursa ne olacak ? Buradaki sıkıntı değişebilecek/geçici bir şeyin yani rollerin kalıtım ile ele alınması
class Person {... }
Teacher : Person {...}
class Student : Person {...}Kalıtımı Bileşim Haline Getirmek
1. Büyük Sınıfları Composition (Birleşim) Haline Getirmek
Bu yöntemde büyük sınıflardaki bazı kodlar XBehavior sınıfına taşınır ve büyük sınıf artık bu kodu çağırır. Açıklaması şöyle.
Bunu yapabilmek için sınıfa bazı attribute/behavior alanları tanımlamak gerekir. Şöyle yaparız
Yine bir sınıftan kalıtım yerine sınıfa yeni şöyle alanlar ekleriz
Örnek - Uzun Inheritance Zinciri
Elimizde şöyle bir kod olsun.
GoF Template Pattern ile ister istemez bir kalıtım oluşuyor. Elimizde şöyle bir kod olsun. Bu kodda esas algoritma Enemy sınıfında. move() metodunda önce Type 2 move yapılıp yapılamayacağı üst sınıfa soruluyor. Cevaba göre Type 1 ve Typ2 move yapılıyor. Ancak Type 3 move de dahil edilmek istenirse işler karışmaya başlıyor.
Multiple inheritance single responsibility kuralını ihlal ediyor gibi görünüyor. Refactoring yaklaşımında multiple inheritance, composition (bileşim) ile değiştiriliyor. Böylece sınıfın tek bir iş yapması sağlanıyor.
Aşağıda multiple inheritance yerine composition getirilmesini gösteren bir örnek var. Sprite sınıfı ilk başta hem Node hem de kaynakları otomatik olarak bırakan Resource sınıfından türüyor.
Composition haline getirmek için önce iki tane arayüz tanımlanıyor.
Elimizde şöyle bir kod olsun.
Composition Over Inheritance Functional Yöntemler yazısına taşıdım
Bu yöntemde büyük sınıflardaki bazı kodlar XBehavior sınıfına taşınır ve büyük sınıf artık bu kodu çağırır. Açıklaması şöyle.
In object-oriented programming, we can use composition in cases where one object "has" (or is part of) another object. Some examples would be:Örnek
- A car has a battery (a battery is part of a car).
- A person has a heart (a heart is part of a person).
- A house has a living room (a living room is part of a house).
Bunu yapabilmek için sınıfa bazı attribute/behavior alanları tanımlamak gerekir. Şöyle yaparız
class Entity
  movable
  harmable
  burnable
  freezable
  ...drunkard = Entity(
  movable=SometimesRandomMovable(),
  harmable=BasicHarmable(),
  burnable=MonsterBurnable(),
  freezable=LoseATurnFreezable()
  ...
)ninja = Entity(
  movable=QuickMovable(),
  harmable=WeakHarmable(),
  burnable=MonsterBurnable(),
  freezable=NotFreezable()
  ...
)Yine bir sınıftan kalıtım yerine sınıfa yeni şöyle alanlar ekleriz
public class Person {
  public MarriageStatus marriageStatus;
  public Race race;
  public Wealth wealth;
}public class MarriageStatus {
  public Datetime anniversary;
  public Person husband;
  public Person wife;
  // TODO: In the future the stakeholder would like to support polyamory
  //  public List<Person> spouses;
}Örnek - Uzun Inheritance Zinciri
Elimizde şöyle bir kod olsun.
public class NamedEntity
{
  public int Id { get; set; }
  public string Name { get; set; }
}public class AuditedEntity : NamedEntity
{
  public DateTime CreatedOn { get; set; }
  public DateTime UpdatedOn { get; set; }
}public class Three : AuditedEntity
{ }public interface INamedEntity
{
  int Id { get; set; }
  string Name { get; set; }
}
public interface IAuditedEntity
{
    DateTime CreatedOn { get; set; }
    DateTime UpdatedOn { get; set; }
}
public class One 
{ }
public class Two : INamedEntity
{
  public int Id { get; set; }
  public string Name { get; set; }
}
public class Three : INamedEntity, IAuditedEntity
{
  public int Id { get; set; }
  public string Name { get; set; }
  DateTime CreatedOn { get; set; }
  DateTime UpdatedOn { get; set; }
}
public class Four : IAuditedEntity
{
    DateTime CreatedOn { get; set; }
    DateTime UpdatedOn { get; set; }
}GoF Template Pattern ile ister istemez bir kalıtım oluşuyor. Elimizde şöyle bir kod olsun. Bu kodda esas algoritma Enemy sınıfında. move() metodunda önce Type 2 move yapılıp yapılamayacağı üst sınıfa soruluyor. Cevaba göre Type 1 ve Typ2 move yapılıyor. Ancak Type 3 move de dahil edilmek istenirse işler karışmaya başlıyor.
abstract class Enemy:
  show()         // Called each game tick
  update()       // Called each game tick
  move()         // Tries alternateMove, if unsuccessful, perform type 1 movement
  abstract alternateMove() // Returns a boolean
class Drunkard extends Enemy:
  alternateMove(): return False
class Mummy extends Enemy:
  alternateMove() // Type 2 movement if in range, otherwise return false
class Ninja extends Enemy:
  alternateMove() // Type 3 movement and return trueabstract class Enemy:
  show()   // Called each game tick
  update() // Called each game tick
  abstract move() // Called in update
class MovementPlanEnemy:
  move() // Type 1 movement
  abstract alternateMove()
class Drunkard extends MovementPlanEnemy:
  alternateMove() // Return false
class Mummy extends MovementPlanEnemy:
  alternateMove() // Tries type 2 movement
class Ninja extends Enemy:
  move() // Type 3 movementabstract class Enemy:
  show()   // Called each game tick
  update() // Called each game tick
  abstract move() // Called in update
class Drunkard extends Enemy:
  move() // Type 1 movement
class Mummy extends Enemy:
  move() // Type 1 + type 2 movement
class Ninja extends Enemy:
  move() // Type 3 movementMultiple inheritance single responsibility kuralını ihlal ediyor gibi görünüyor. Refactoring yaklaşımında multiple inheritance, composition (bileşim) ile değiştiriliyor. Böylece sınıfın tek bir iş yapması sağlanıyor.
Aşağıda multiple inheritance yerine composition getirilmesini gösteren bir örnek var. Sprite sınıfı ilk başta hem Node hem de kaynakları otomatik olarak bırakan Resource sınıfından türüyor.
Composition haline getirmek için önce iki tane arayüz tanımlanıyor.
// traditional part
interface Node {
  Position getPosition();
  // anything else
}
interface Resource {
  void allocate(...);
  void destroy();
}// composition interfaces
interface NodeHolder {
  Node asNode(); // the only method
}
interface ResourceHolder {
  Resource asResource(); // the only method
}class Sprite 
  extends Node 
  implements NodeHolder, ResourceHolder 
{
  private Resource my_resource;
  public Sprite(...) {
    // whatever construction needed
    my_resource = new ResourceImpl();
  }Elimizde şöyle bir kod olsun.
class Application implements DatabaseReader, DatabaseWriter, UserInteraction,
  Visualizer {
    ...
}interface DatabaseReader { String read(); }
interface DatabaseWriter { void write(String s); }
class Database {
    DatabaseConnection connection = create();
    DatabaseReader reader = createReader(connection);
    DatabaseReader writer = createWriter(connection);
    DatabaseReader getReader() { return reader; }
    DatabaseReader getWriter() { return writer; }
}Composition Over Inheritance Functional Yöntemler yazısına taşıdım
 
 
Hiç yorum yok:
Yorum Gönder