SOLID-Interface Segregation Principle

 

SOLID tasarım ilkeleri Robert C. Martin tarafından geliştirildi ve nesne yönelimli yazılım geliştirmede en iyi bilinen tasarım ilkelerinden bazıları. SOLID, aşağıdaki beş prensip için hatırlatıcı bir kısaltmadır:

Bu ilke , Xerox'un yeni yazıcı sistemleri için yazılımı oluşturmalarına yardımcı olmak için danışmanlık yaparken, Robert C. Martin tarafından belirlendi. Bunu şöyle tanımladı:

 “Müşteriler, kullanmadıkları arayüzlere bağlı olmaya zorlanmamalıdır.”

Bu makalede size göstereceğim gibi, özellikle yazılımınız geliştikçe ve daha fazla özellik eklemeniz gerekiyorsa, bu ilkeyi  ihlal etmek oldukça kolaydır.

Single Responsibility ilkesine benzer şekilde,  Interface Segregation İlkesinin amacı yazılımı çok sayıda bağımsız bölüme ayırarak gerekli değişikliklerin yan etkilerini ve sıklığını azaltmaktır.

Aşağıdaki örnekte göstereceğim gibi, bu yalnızca interface yapısını belirli bir istemci veya görevi yerine getirecek şekilde tanımladığınızda gerçekleştirilebilir.

Interface Segregation Principle ihlali:Bir uygulamanın birçok yıl boyunca kullanılmasının ve kullanıcılarının düzenli olarak yeni özellikler talep etmesi oldukça sık görülür.

İş açısından bakıldığında, bu harika bir durum. Ancak teknik açıdan bakıldığında, her değişikliğin uygulanması bir risk taşımaktadır. Farklı bir sorumluluk getirmesine ve yeni bir interface’de daha iyi bir şekilde ayrılmasına rağmen, mevcut bir interface yeni bir yöntem eklemek caziptir. Bu çoğu zaman, çeşitli sorumluluklar uygulayan yöntemler içeren şişirilmiş arayüzlere yol açan, interface kirliliğinin başlangıcıdır.

Basit bir örneğe bakalım.

Başlangıçta, proje temel bir kahve makinesini modellemek için BasicCoffeeMachine sınıfını kullanmakta. Lezzetli bir filtre kahve demlemek için öğütülmüş kahve kullanır.

   class BasicCoffeeMachine : CoffeeMachine

    {  private Map<CoffeeSelection, Configuration> configMap;

        private GroundCoffee groundCoffee;

        private BrewingUnit brewingUnit;

         public void addGroundCoffee(GroundCoffee newCoffee)

        {

            throw new NotImplementedException();

        }

        public CoffeeDrink brewFilterCoffee()

        {

            throw new NotImplementedException();

        }

    }

O zaman, CoffeeMachine interface’sini addGroundCoffee ve brewFilterCoffee yöntemleriyle implement etmek mantıklı . Bunlar bir kahve makinesinin iki temel metodudur ve gelecekteki tüm kahve makineleri tarafından uygulanmalıdır.

   public interface CoffeeMachine

    {

        CoffeeDrink brewFilterCoffee() throws CoffeeException;

        void addGroundCoffee(GroundCoffee newCoffee) throws CoffeeException;

    }

Fakat sonra birisi, uygulamanın espresso makinelerini de desteklemesi gerektiğine karar verdi. Geliştirme ekibi , aşağıdaki kod örneğinde görebileceğiniz EspressoMachine sınıfı olarak modelledi . BasicCoffeeMachine sınıfına benziyor .

public class EspressoMachine : CoffeeMachine

    {

        public void addGroundCoffee(GroundCoffee newCoffee)

        {

            throw new NotImplementedException();

        }

 

        public CoffeeDrink brewFilterCoffee()

        {

            throw new NotImplementedException();

        }

    }

Geliştirici, espresso makinesinin sadece farklı bir kahve makinesi olduğuna karar verdi. Yani, CoffeeMachine arayüzünü uygulamak zorunda olduğunu gördü.

 

Tek fark, brewEspresso yöntem EspressoMachine sınıfı yerine uygulayan brewFilterCoffee yöntemi. Şimdilik İlkesimizi göz ardı edelim ve aşağıdaki üç değişikliği gerçekleştirelim:

1-EspressoMachine class uygulayan coffeemachine interface ve brewFilterCoffee metodu.

public CoffeeDrink brewFilterCoffee()

        {

            throw new NotImplementedException();

 

        }

2-CoffeeMachine interface’sine brewEspresso yöntemini ekliyoruz, böylece interface  bir espresso demlemenize izin veriyor.

  public interface CoffeeMachine

        {

 

            CoffeeDrink brewFilterCoffee();

            void addGroundCoffee(GroundCoffee newCoffee);

            CoffeeDrink brewEspresso();

        }

3- CoffeeMachine interface  tarafından tanımlandığı için, BasicCoffeeMachine sınıfında brewEspresso yöntemini uygulamanız gerekir.

   public CoffeeDrink brewEspresso()

        {

            throw new NotImplementedException();

        }

Özellikle 2. ve 3. değişiklikler, CoffeeMachine interfacenin bu iki kahve makinesi için uygun olmadığını gösteriyor.Makinanın kullanmadığı ve yapamayacağı bir özellik eklenmesi karmaşıklığa neden olacaktır.

Doğru yapı nasıl olmalı:

CoffeMachine interfacesini ve uygulamalarını BasicCoffeeMachine ve EspressoMachine ile nasıl düzeltebilirsiniz ?

CoffeeMachine interface yapısını farklı türde kahve makineleri için çoklu interface yapılarına ayırmanız gerekir . Arayüzün bilinen tüm uygulamaları addGroundCoffee yöntemini uygular . Yani, onu kaldırmak için bir sebep yoktur.

  public interface ICoffeeMachine

    {

 

        void addGroundCoffee(GroundCoffee newCoffee);

    }

BrewFilterCoffee ve brewEspresso yöntemleri için durum böyle değil . Bunları birbirinden ayırmak için iki yeni interface oluşturmalısınız. Ve bu örnekte, bu iki interface de CoffeeMachine arayüzünü genişletmelidir .  

Yeni interface yapılar bu şekilde olacak:

public interface IFilterCoffeeMachine : ICoffeeMachine

    {

 

        CoffeeDrink brewFilterCoffee();

    }

public interface IEspressoCoffeeMachine :ICoffeeMachine

    {

 

        CoffeeDrink brewEspresso();

    }

Özet

SOLID tasarım ilkeleri, sağlam ve bakımı yapılabilir uygulamaları yazmanıza yardımcı olur. Bu yazıda, Robert C. Martin'in aşağıdaki gibi tanımladığı Inerface Segregation İlkesine ayrıntılı bir şekilde baktık:

 “Müşteriler, kullanmadıkları arayüzlere bağlı olmaya zorlanmamalıdır.”