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. Az alapelv eredeti angol megfogalmazása: „Program to an interface, not an implementation”, azaz "Interfészre programozzunk, ne pedig implementációra! . Öröklődés során minden, az absztrakt műveletek konkretizálását végző osztály osztozik az interfészen, vagyis az interfészen változtatni az alosztályok illetve implementációs osztályok nem tudnak (még elrejteni sem tudják az öröklött/kapott műveleteket!). A konkrét osztályok „mindössze” új műveleteket adhatnak hozzá, illetve a meglévőket felüldefiniálhatják. Így viszont minden alosztály tud majd válaszolni az interfésznek megfelelő kérelmekre, amik lehetővé teszik, hogy a kliensek függetlenek legyenek az általuk felhasznált objektumok tényleges típusától (nem is kell őket ismerniük, így ez a lazán csatolás irányába tett nagy lépésként is értelmezhető), amíg az interfész megfelel a kliens által vártnak. A kliens így csak az interfésztől függ, és nem az implementációtól, vagyis anélkül cserélhetőek le a szolgáltatást nyújtó konkrét osztályok az interfész változatlanul hagyása melle

Akkor kényszerülünk implementációra programozni, ha az osztály felelősségi körét rosszul határoztuk meg és egy osztály több felelősségi kört is lefed (ami ellent mond az egy felelősség elvének - SRP), vagy egy felelősséget sem fed le teljesen. Ha a kódunkban találunk olyan részt, amely egy másik osztályra implementációjától függ, akkor az hibás tervre utal.

Ha implementációra programozunk és megváltozik az osztály, akkor a vele kapcsolatban álló osztályoknak is változniuk kell. Viszont, ha felületre programozunk, és megváltozik az implementáció, de a felület nem, akkor nem kell megváltoztatni a többi osztályt!

Az interfészre való programozás előnyei közé tartozik a

karbantarthatóságtt, hogy az a kliensekre bármiféle kihatással lenne.

Programozási példák szerkesztés

Példa implementációra való programozásra (GoF 1 ellenpélda) szerkesztés

C# szerkesztés

class LoggerRossz
    {
        // Mi van akkor ha én például egyéb módon is szeretnék logolni?
        public void LogÜzenet(string üzenet)
        {
            // Logold ide ezt az üzenetet
        }

        public string[] KéremAzUtolsó10Üzenetet()
        {
            // mi van akkor, ha az osztály valamiért megváltozik
            // és ez a metódus valamiért később List<string>-et ad vissza tömb helyett?
            // Mindenhol át kéne írnunk a kódot, ahol meghívtuk ezt a funkciót!
            return new string[]
            {
                "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
            };
        }
    }

    class ValamilyenOsztály
    {
        public void ValamilyenMetódus()
        {
            LoggerRossz logger = new LoggerRossz();
            string[] logs = logger.KéremAzUtolsó10Üzenetet();

            foreach (string s in logs)
            {
                Console.WriteLine(s);
            }
        }
    }

Példa interfészre való programozásra (GoF 1) szerkesztés

C# szerkesztés

interface ILogger
{
    void LogÜzenet(string msg);
    IEnumerable<string> KéremAzUtolsó10Üzenetet();
}

class LoggerJó : ILogger
{
    public void LogÜzenet(string üzenet)
    {
        // Logold ide az üzenetet
    }

    // Itt is figyelünk arra, hogy interfészre programozzunk!
    // Tehát később, mikor valahol meghívjuk ezt a metódust
    // bármilyen konkrét osztály bírja majd ezt kezelni, 
    // ami implementálta az IEnumerable interfészt!
    public IEnumerable<string> KéremAzUtolsó10Üzenetet()
    {
        return new string[]
        {
           "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
        };
    }
}

// Bővíthetőség
class LogoljFelhőbe : ILogger
{
    public void LogÜzenet(string üzenet)
    {
        // A felhőbe logoláshoz használj valamilyen web szolgáltatást
    }

    public IEnumerable<string> GetLast10Messages()
    {
        // hívj meg valamilyen web szolgáltatást és fecskendezd be az adatokat
        return new string[]
        {
            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
        };
    }
}

class ValamilyenOsztály
{
    // A paraméterben megadott logger tehát lehet bármilyen konkrét logger
    // példány, ami implementálta az ILogger interfészt
    // (pl ValamilyenMetódus(new LogoljFelhőbe()))
    public void ValamilyenMetódus(ILogger _logger)
    {
        ILogger logger = _logger();
        IEnumerable<string> logs = logger.KéremAzUtolsó10Üzenetet();

        foreach (string s in logs)
        {
            Console.WriteLine(s);
        }
    }
}

class ValamilyenOsztály2
{
    public void ValamilyenMetódus(ILogger _logger)
    {
        ILogger logger = _logger;
        IEnumerable<string> logs = logger.KéremAzUtolsó10Üzenetet();

        foreach (string s in logs)
        {
            Console.WriteLine(s);
        }
    }
}


Kapcsolódó szócikkek szerkesztés

Források szerkesztés

  • Gamma, Helm, Johnson & Vlissides. Design Patterns (könyv). Addison-Wesley (1994). ISBN 0-201-63361-2 
  • Dr. Kusper Gábor. Programozási technológiák (jegyzet) (2015) 
  • Kollár Lajos, Sterbinszky Nóra. Programozási technológiák (jegyzet) (2014)