Keri sisuni

Liidesed

Abstraktsest klassist saab minna veel üldisemaks ja abstraktsemaks ning kasutada liideseid (interface), mis määravad ära ainult selle millised liikmed klassil peavad olema. Liidese kohta kasutatakse ka terminit contract, mis tõlkes tähendab lepingut. Liides on seega omamoodi leping, mis klassi küljes olles ütleb, et millised liikmed sellel klassil peavad olema, et leping oleks täidetud. Kui klass lepingut ei täida, siis tekib viga juba kompileerimisel.

Meenutame Päriluse peatüki praktilisest näitest abstraktset klassi BaseLogger.

public abstract class BaseLogger
{
    public abstract void Info(string message);
    public abstract void Error(string message);
}

Sellel klassil pole ühtegi liiget, mis sisaldaks koodi ja seega pole meil ühtegi head põhjust miks mitte kasutada selle klassi asemel liidest. Defineerime BaseLogger põhjal ILogger liidese.

public interface ILogger
{
    void Info(string message);
    void Error(string message);
}

Liidese lisamine klassile

Liidese kasutamiseks kasutame sama süntaksit nagu klassi laiendamise korral (öeldakse ka nii, et klass laiendab liidest).

public interface ILogger
{
    void Info(string message);
    void Error(string message);
}

public class DebugLogger : ILogger
{
    public void Info(string message)
    {
        Debug.WriteLine("INFO: " + message);
    }

    public void Error(string message)
    {
        Debug.WriteLine("ERROR: " + message);
    }
}

public class ConsoleLogger : ILogger
{
    public void Info(string message)
    {
        Console.WriteLine("INFO: " + message);
    }

    public void Error(string message)
    {
        Console.WriteLine("ERROR: " + message);
    }
}

Mitme liidese kasutamine

Klassid võivad kasutada ka mitut liidest. Reegel on selline: klass võib pärida ainult ühest klassist, kuid kasutada mitut liidest. Lisame uue loggeri, millel on päriselt mitut liidest vaja. Olgu selleks FileLogger, mis kirjutab teated logifaili. Kuna FileLogger kasutab failisüsteemi ja failisüsteemiga suhtlemiseks mõeldud objektidel on Dispose() meetod, peab FileLogger kasutama ka IDisposable liidest, et programmi töö lõpus failisüsteemi ressursid vabaks anda.

public class FileLogger : ILogger, IDisposable
{
    private readonly FileStream _fileStream;
    private readonly StreamWriter _streamWriter;

    public FileLogger(string fileName)
    {
        _fileStream = new FileStream(fileName, FileMode.OpenOrCreate);
        _fileStream.Seek(0, SeekOrigin.End);

        _streamWriter = new StreamWriter(_fileStream);
    }

    public void Info(string message)
    {
        _streamWriter.WriteLine("INFO: " + message);
    }

    public void Error(string message)
    {
        _streamWriter.WriteLine("ERROR: " + message);
    }

    public void Dispose()
    {
        _streamWriter.Flush();
        _streamWriter.Dispose();
        _fileStream.Dispose();
    }
}

ILogger logger = new FileLogger("log.txt");

logger.Info("Program started");
// ...
logger.Info("Program finished");

logger.Dispose();
using System;
using System.IO;

namespace OOP
{
    public interface ILogger
    {
        void Info(string message);
        void Error(string message);
    }

    public class FileLogger : ILogger, IDisposable
    {
        private readonly FileStream _fileStream;
        private readonly StreamWriter _streamWriter;

        public FileLogger(string fileName)
        {
            _fileStream = new FileStream(fileName, FileMode.OpenOrCreate);
            _fileStream.Seek(0, SeekOrigin.End);

            _streamWriter = new StreamWriter(_fileStream);
        }

        public void Info(string message)
        {
            _streamWriter.WriteLine("INFO: " + message);
        }

        public void Error(string message)
        {
            _streamWriter.WriteLine("ERROR: " + message);
        }

        public void Dispose()
        {
            _streamWriter.Flush();
            _streamWriter.Dispose();
            _fileStream.Dispose();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ILogger logger = new FileLogger("log.txt");

            logger.Info("Program started");
            // ...
            logger.Info("Program finished");

            logger.Dispose();
        }
    }
}

Liideste pärilus

Klasside tasemel on meil pärilus juba selge. Sarnaselt töötab pärilus ka liideste tasemel.

Vaatame ühte klassikalist juhtumit, kus meil on liides, mis pärib IDisposable liidesest. Lisaks on meil klassid, milledest osadel on IDisposable liidest vaja ja teistel mitte. Kasutame seni kirjutatud logimise klasse ja logimise liidest.

public interface ILogger : IDisposable
{
    void Info(string message);
    void Error(string message);
}

public class DebugLogger : ILogger
{
    public void Info(string message)
    {
        Debug.WriteLine("INFO: " + message);
    }

    public void Error(string message)
    {
        Debug.WriteLine("ERROR: " + message);
    }

    public void Dispose()
    {
    }
}

public class ConsoleLogger : ILogger
{
    public void Info(string message)
    {
        Console.WriteLine("INFO: " + message);
    }

    public void Error(string message)
    {
        Console.WriteLine("ERROR: " + message);
    }

    public void Dispose()
    {
    }
}

public class FileLogger : ILogger, IDisposable
{
    private readonly FileStream _fileStream;
    private readonly StreamWriter _streamWriter;

    public FileLogger(string fileName)
    {
        _fileStream = new FileStream(fileName, FileMode.OpenOrCreate);
        _fileStream.Seek(0, SeekOrigin.End);

        _streamWriter = new StreamWriter(_fileStream);
    }

    public void Info(string message)
    {
        _streamWriter.WriteLine("INFO: " + message);
    }

    public void Error(string message)
    {
        _streamWriter.WriteLine("ERROR: " + message);
    }

    public void Dispose()
    {
        _streamWriter.Flush();
        _streamWriter.Dispose();
        _fileStream.Dispose();
    }
}

var loggers = new ILogger[] 
{ 
    new DebugLogger(), 
    new ConsoleLogger(), 
    new FileLogger("log.txt") 
};

foreach(var logger in loggers)
{
    logger.Info("Hello from loop!");
}

foreach(var logger in loggers)
{
    logger.Dispose();
}
using System;
using System.Diagnostics;
using System.IO;

namespace OOP
{
    public interface ILogger : IDisposable
    {
        void Info(string message);
        void Error(string message);
    }

    public class DebugLogger : ILogger
    {
        public void Info(string message)
        {
            Debug.WriteLine("INFO: " + message);
        }

        public void Error(string message)
        {
            Debug.WriteLine("ERROR: " + message);
        }

        public void Dispose()
        {
        }
    }

    public class ConsoleLogger : ILogger
    {
        public void Info(string message)
        {
            Console.WriteLine("INFO: " + message);
        }

        public void Error(string message)
        {
            Console.WriteLine("ERROR: " + message);
        }

        public void Dispose()
        {
        }
    }

    public class FileLogger : ILogger, IDisposable
    {
        private readonly FileStream _fileStream;
        private readonly StreamWriter _streamWriter;

        public FileLogger(string fileName)
        {
            _fileStream = new FileStream(fileName, FileMode.OpenOrCreate);
            _fileStream.Seek(0, SeekOrigin.End);

            _streamWriter = new StreamWriter(_fileStream);
        }

        public void Info(string message)
        {
            _streamWriter.WriteLine("INFO: " + message);
        }

        public void Error(string message)
        {
            _streamWriter.WriteLine("ERROR: " + message);
        }

        public void Dispose()
        {
            _streamWriter.Flush();
            _streamWriter.Dispose();
            _fileStream.Dispose();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var loggers = new ILogger[]
            {
                new DebugLogger(),
                new ConsoleLogger(),
                new FileLogger("log.txt")
            };

            foreach (var logger in loggers)
            {
                logger.Info("Hello from loop!");
            }

            foreach (var logger in loggers)
            {
                logger.Dispose();
            }
        }
    }
}

Viited