Encapsulation

Encapsulation är som att ha en säkerhetsvakt för din kod! Du bestämmer vad som får komma in, vad som får gå ut, och vad som ska vara hemligt. Som James Bond för dina variabler! 🕵️‍♂️

🎯 Efter denna artikel kommer du att:

  • Förstå encapsulation konceptet - information hiding på svenska! 🙈
  • Använda access modifiers - public, private, protected som en pro 🔑
  • Skapa properties med getters/setters - controlled access patterns 🎛️
  • Designa secure classes - protect your data like Fort Knox! 🏛️

🔒 Access Modifiers - Säkerhetsnivåer

🌟 Public - Öppen för alla


public class Restaurant
{
    public string Name { get; set; }        // Alla kan se och ändra
    public string Address { get; set; }     // Helt öppet

    public void TakeOrder(string dish)      // Alla kan beställa
    {
        Console.WriteLine($"🍽️ Order: {dish} received!");
    }

    public void ShowMenu()                  // Alla kan se menyn
    {
        Console.WriteLine("📋 Today's menu: Pizza, Pasta, Salad");
    }
}

// Usage - anyone can access
Restaurant restaurant = new Restaurant();
restaurant.Name = "Mario's Pizza";          // ✅ OK - public
restaurant.TakeOrder("Pizza Margherita");  // ✅ OK - public method

🔒 Private - Strikt hemligt


public class ATM
{
    // Private fields - bara denna klass kan använda
    private decimal _totalCash = 100000;
    private string _adminPin = "1337";
    private List<string> _transactionLog = new();

    public void WithdrawCash(decimal amount, string userPin)
    {
        if (ValidateTransaction(amount) && AuthenticateUser(userPin))
        {
            _totalCash -= amount;  // ✅ Private field - OK from inside class
            LogTransaction($"Withdrawal: {amount}");  // ✅ Private method - OK
            Console.WriteLine($"💰 Dispensing {amount:C}");
        }
        else
        {
            Console.WriteLine("❌ Transaction denied!");
        }
    }

    // Private methods - internal logic
    private bool ValidateTransaction(decimal amount)
    {
        return amount > 0 && amount <= _totalCash && amount <= 5000;
    }

    private bool AuthenticateUser(string pin)
    {
        // In real life: check against database
        return pin.Length == 4;  // Simplified
    }

    private void LogTransaction(string transaction)
    {
        _transactionLog.Add($"{DateTime.Now}: {transaction}");
    }

    // Public method to get limited info
    public string GetATMStatus()
    {
        return $"ATM operational. Cash available: {_totalCash > 1000}";
    }
}

// Usage - limited access
ATM atm = new ATM();
atm.WithdrawCash(500, "1234");         // ✅ OK - public method

// atm._totalCash = 0;                 // ❌ Compilation error - private!
// atm.ValidateTransaction(100);       // ❌ Compilation error - private method!

🔐 Protected - Bara familjen


public class Vehicle  // Parent class
{
    protected string _engineType = "V6";     // Bara family kan använda
    protected int _maxSpeed = 120;           // Children kan accessa
    private string _chassisNumber = "ABC123"; // Bara Vehicle class

    public void StartEngine()
    {
        Console.WriteLine($"🚗 Starting {_engineType} engine");
        InitializeSystem();  // ✅ Protected method from same class
    }

    protected void InitializeSystem()  // Children kan override/använda detta
    {
        Console.WriteLine("🔧 System initialized");
    }
}

public class SportsCar : Vehicle  // Child class
{
    public void ActivateTurbo()
    {
        if (_maxSpeed > 200)  // ✅ Protected field - OK from child
        {
            Console.WriteLine($"🚀 Turbo activated! Max speed: {_maxSpeed} km/h");
            InitializeSystem();  // ✅ Protected method - OK from child
        }

        // Console.WriteLine(_chassisNumber);  // ❌ Error - private field!
    }

    protected override void InitializeSystem()  // Override protected method
    {
        base.InitializeSystem();
        Console.WriteLine("🏎️ Sports car systems online!");
    }
}

🎯 Hands-On Workshop: Smart Home System


using System;
using System.Collections.Generic;
using System.Linq;

public class SmartHome
{
    // Private fields - internal state
    private Dictionary<string, SmartDevice> _devices;
    private string _ownerName;
    private bool _securityEnabled;
    private List<string> _securityLog;

    // Public properties med validation
    public string OwnerName
    {
        get => _ownerName;
        set => _ownerName = !string.IsNullOrWhiteSpace(value) ? value : "Unknown Owner";
    }

    public bool SecurityEnabled
    {
        get => _securityEnabled;
        set
        {
            if (_securityEnabled != value)
            {
                _securityEnabled = value;
                LogSecurityEvent($"Security {(value ? "ENABLED" : "DISABLED")}");
                NotifyAllDevices($"Security mode: {(value ? "ON" : "OFF")}");
            }
        }
    }

    // Read-only properties
    public int DeviceCount => _devices.Count;
    public string SystemStatus
    {
        get
        {
            var activeDevices = _devices.Values.Count(d => d.IsActive);
            return $"🏠 {OwnerName}'s Home: {activeDevices}/{DeviceCount} devices active, Security: {(_securityEnabled ? "🔒" : "🔓")}";
        }
    }

    public SmartHome(string ownerName)
    {
        OwnerName = ownerName;  // Uses property validation
        _devices = new Dictionary<string, SmartDevice>();
        _securityLog = new List<string>();
        _securityEnabled = false;
    }

    // Public methods - controlled interface
    public void AddDevice(SmartDevice device)
    {
        if (device == null)
        {
            Console.WriteLine("❌ Cannot add null device");
            return;
        }

        if (_devices.ContainsKey(device.Name))
        {
            Console.WriteLine($"⚠️ Device '{device.Name}' already exists");
            return;
        }

        _devices[device.Name] = device;
        device.SetHome(this);  // Let device know which home it belongs to
        Console.WriteLine($"✅ Added device: {device.Name}");
        LogSecurityEvent($"Device added: {device.Name}");
    }

    public void ControlDevice(string deviceName, string command)
    {
        if (!_devices.ContainsKey(deviceName))
        {
            Console.WriteLine($"❌ Device '{deviceName}' not found");
            return;
        }

        var device = _devices[deviceName];
        device.ExecuteCommand(command);
        LogSecurityEvent($"Command '{command}' sent to {deviceName}");
    }

    public void ShowDevices()
    {
        Console.WriteLine($"\n🏠 {SystemStatus}");
        Console.WriteLine("📱 Devices:");
        foreach (var device in _devices.Values)
        {
            Console.WriteLine($"  {device.GetStatusDisplay()}");
        }
    }

    public void ShowSecurityLog(int lastEntries = 5)
    {
        Console.WriteLine($"\n🛡️ Security Log (last {lastEntries} entries):");
        var entries = _securityLog.TakeLast(lastEntries);
        foreach (var entry in entries)
        {
            Console.WriteLine($"  {entry}");
        }
    }

    // Private methods - internal logic
    private void LogSecurityEvent(string eventDescription)
    {
        var logEntry = $"[{DateTime.Now:HH:mm:ss}] {eventDescription}";
        _securityLog.Add(logEntry);
    }

    private void NotifyAllDevices(string message)
    {
        foreach (var device in _devices.Values)
        {
            device.ReceiveNotification(message);
        }
    }
}

public abstract class SmartDevice
{
    // Protected fields - family can access
    protected string _name;
    protected bool _isActive;
    protected SmartHome _parentHome;

    // Private fields - device secrets
    private string _deviceId = Guid.NewGuid().ToString()[..8];
    private DateTime _lastActivity = DateTime.Now;

    // Public properties
    public string Name => _name;
    public bool IsActive => _isActive;
    public string DeviceId => _deviceId;  // Read-only exposure of private field

    protected SmartDevice(string name)
    {
        _name = name ?? "Unknown Device";
        _isActive = false;
    }

    // Public interface
    public void SetHome(SmartHome home)
    {
        _parentHome = home;
    }

    public abstract void ExecuteCommand(string command);

    public virtual string GetStatusDisplay()
    {
        var status = _isActive ? "🟢 ON" : "🔴 OFF";
        return $"{status} {_name} (ID: {_deviceId})";
    }

    public virtual void ReceiveNotification(string message)
    {
        Console.WriteLine($"📢 {_name} received: {message}");
    }

    // Protected methods - children can use
    protected void UpdateActivity()
    {
        _lastActivity = DateTime.Now;
    }

    protected void LogDeviceAction(string action)
    {
        Console.WriteLine($"📝 [{DateTime.Now:HH:mm:ss}] {_name}: {action}");
        UpdateActivity();
    }
}

public class SmartLight : SmartDevice
{
    private int _brightness = 100;
    private string _color = "white";

    public int Brightness
    {
        get => _brightness;
        private set => _brightness = Math.Max(0, Math.Min(100, value));
    }

    public string Color
    {
        get => _color;
        private set => _color = value ?? "white";
    }

    public SmartLight(string name) : base(name) { }

    public override void ExecuteCommand(string command)
    {
        var parts = command.ToLower().Split(' ');

        switch (parts[0])
        {
            case "on":
                _isActive = true;
                LogDeviceAction("Light turned ON");
                break;

            case "off":
                _isActive = false;
                LogDeviceAction("Light turned OFF");
                break;

            case "brightness":
                if (parts.Length > 1 && int.TryParse(parts[1], out int brightness))
                {
                    Brightness = brightness;
                    LogDeviceAction($"Brightness set to {_brightness}%");
                }
                break;

            case "color":
                if (parts.Length > 1)
                {
                    Color = parts[1];
                    LogDeviceAction($"Color changed to {_color}");
                }
                break;

            default:
                Console.WriteLine($"❌ Unknown command: {command}");
                break;
        }
    }

    public override string GetStatusDisplay()
    {
        var baseStatus = base.GetStatusDisplay();
        if (_isActive)
            return $"{baseStatus} - {_brightness}% {_color}";
        return baseStatus;
    }
}

public class SmartThermostat : SmartDevice
{
    private double _currentTemp = 20.0;
    private double _targetTemp = 22.0;

    public double CurrentTemperature => _currentTemp;

    public double TargetTemperature
    {
        get => _targetTemp;
        set
        {
            if (value < 10 || value > 30)
            {
                Console.WriteLine("⚠️ Temperature must be between 10-30°C");
                return;
            }
            _targetTemp = value;
            LogDeviceAction($"Target temperature set to {_targetTemp}°C");
        }
    }

    public SmartThermostat(string name) : base(name)
    {
        _isActive = true;  // Thermostats are always active
    }

    public override void ExecuteCommand(string command)
    {
        var parts = command.ToLower().Split(' ');

        switch (parts[0])
        {
            case "temp":
            case "temperature":
                if (parts.Length > 1 && double.TryParse(parts[1], out double temp))
                {
                    TargetTemperature = temp;
                }
                break;

            case "status":
                var diff = _targetTemp - _currentTemp;
                var status = Math.Abs(diff) < 0.5 ? "Perfect" :
                           diff > 0 ? $"Heating (+{diff:F1}°C)" :
                           $"Cooling ({diff:F1}°C too warm)";
                Console.WriteLine($"🌡️ Current: {_currentTemp}°C, Target: {_targetTemp}°C - {status}");
                break;

            default:
                Console.WriteLine($"❌ Unknown thermostat command: {command}");
                break;
        }
    }
}

// Demo program
class Program
{
    static void Main()
    {
        Console.WriteLine("🏠 SMART HOME SYSTEM DEMO 🏠");
        Console.WriteLine("============================");

        // Create smart home
        var home = new SmartHome("Marcus Medina");

        // Add devices
        home.AddDevice(new SmartLight("Living Room Light"));
        home.AddDevice(new SmartLight("Bedroom Light"));
        home.AddDevice(new SmartThermostat("Main Thermostat"));

        // Show initial status
        home.ShowDevices();

        Console.WriteLine("\n🎮 Controlling devices:");
        // Control devices
        home.ControlDevice("Living Room Light", "on");
        home.ControlDevice("Living Room Light", "brightness 75");
        home.ControlDevice("Living Room Light", "color blue");

        home.ControlDevice("Bedroom Light", "on");

        home.ControlDevice("Main Thermostat", "temperature 24");
        home.ControlDevice("Main Thermostat", "status");

        // Enable security
        Console.WriteLine("\n🔒 Enabling security:");
        home.SecurityEnabled = true;

        // Show final status
        home.ShowDevices();
        home.ShowSecurityLog();
    }
}

🔄 Encapsulation vs Other OOP Principles

Encapsulation + Inheritance


public class Vehicle
{
    protected string _make;      // Children can access
    private string _vin;         // Only Vehicle class

    public string Make => _make; // Public getter

    protected Vehicle(string make, string vin)
    {
        _make = make ?? "Unknown";
        _vin = vin ?? GenerateVIN();
    }

    private string GenerateVIN() => Guid.NewGuid().ToString()[..17];
}

public class Car : Vehicle
{
    public Car(string make, string vin) : base(make, vin)
    {
        // Can access _make (protected) but not _vin (private)
        Console.WriteLine($"Created car: {_make}");
    }
}

Encapsulation + Polymorphism


public abstract class Shape
{
    protected double _area;  // Calculated by children

    public double Area => _area;  // Read-only access

    public abstract void CalculateArea();  // Each shape calculates differently

    protected void ValidateDimension(double value, string dimensionName)
    {
        if (value <= 0)
            throw new ArgumentException($"{dimensionName} must be positive");
    }
}

public class Circle : Shape
{
    private double _radius;

    public double Radius
    {
        get => _radius;
        set
        {
            ValidateDimension(value, "Radius");  // Use protected method
            _radius = value;
            CalculateArea();  // Recalculate when changed
        }
    }

    public Circle(double radius)
    {
        Radius = radius;  // Uses property validation
    }

    public override void CalculateArea()
    {
        _area = Math.PI * _radius * _radius;
    }
}

💡 Marcus Encapsulation Wisdom

“Encapsulation är som att vara bouncer på en nattklubb - du kontrollerar vem som får komma in, vad de får göra, och vad som ska hållas hemligt! Good bouncers make good code!” 🕺💂

Real story: Första gången jag lät allt vara public (2001) för att “det var enklare”… tre månader senare hade någon annan utvecklare förstört min class genom att sätta balance = -999999. Sen dess: encapsulation EVERYWHERE! 🛡️

Pro tip: Start med allt private, sedan öppna upp bara det som BEHÖVER vara åtkomligt. Det är lättare att göra saker mer öppna än att stänga igen säkerhetshål senare! 🔐

Ready för Polymorphism och Interfaces? Encapsulation är fundamentet - nu blir det riktigt kraftfullt! 🎭


Upp

Upp


Licens: Apache 2.0 | © 2023 Marcus Medina, Campus Mölndal. Alla rättigheter förbehållna.
Du får använda och modifiera detta verk enligt villkoren i Apache License, Version 2.0. Du får inte använda detta verk för kommersiella ändamål utan tillstånd från upphovsmannen.