Low-level design: Bir otopark (parking lot) sistemini nesne yönelimli olarak tasarlayın.
Cevap
LLD sorularında beklenen; gereksinimleri netleştirmek, ana sınıfları ve ilişkilerini çıkarmak, uygun desenleri seçmek ve kritik metotları kodlamaktır. Mükemmel bir UML değil, mantıklı sorumluluk dağılımı aranır.
1. Gereksinimleri netleştirin
- Birden fazla kat, her katta farklı boyutta yerler (motosiklet, kompakt, büyük).
- Araç girişte bilet alır, çıkışta süreye göre ücret öder.
- Uygun yer yoksa giriş reddedilir; anlık boş yer sayısı gösterilir.
- Kapsam dışı (sorun): rezervasyon, çoklu giriş kapısında eşzamanlılık detayları.
2. Ana sınıflar
| Sınıf | Sorumluluk |
|---|---|
ParkingLot | Katları yönetir, giriş/çıkış akışını koordine eder |
Level | Kendi yerlerini tutar, uygun yer bulur |
ParkingSpot | Boyut, dolu/boş durumu, park etmiş araç |
Vehicle | Plaka ve boyut (Motorcycle, Car, Truck) |
Ticket | Araç, yer, giriş zamanı |
PricingStrategy | Ücret hesaplama (Strategy deseni) |
3. Kod iskeleti
from enum import Enum
from datetime import datetime
from abc import ABC, abstractmethod
import math, uuid
class Size(Enum):
SMALL = 1; MEDIUM = 2; LARGE = 3
class Vehicle:
def __init__(self, plate: str, size: Size):
self.plate, self.size = plate, size
class ParkingSpot:
def __init__(self, spot_id: str, size: Size):
self.id, self.size, self.vehicle = spot_id, size, None
def can_fit(self, v: Vehicle) -> bool:
return self.vehicle is None and v.size.value <= self.size.value
class Level:
def __init__(self, spots):
self.spots = spots
def find_spot(self, v):
return next((s for s in self.spots if s.can_fit(v)), None)
class Ticket:
def __init__(self, vehicle, spot):
self.id = str(uuid.uuid4())
self.vehicle, self.spot, self.entry = vehicle, spot, datetime.now()
class PricingStrategy(ABC):
@abstractmethod
def price(self, ticket: Ticket, exit_time: datetime) -> float: ...
class HourlyPricing(PricingStrategy):
RATES = {Size.SMALL: 20, Size.MEDIUM: 40, Size.LARGE: 80}
def price(self, ticket, exit_time):
hours = math.ceil((exit_time - ticket.entry).total_seconds() / 3600) or 1
return hours * self.RATES[ticket.vehicle.size]
class ParkingLot:
def __init__(self, levels, pricing: PricingStrategy):
self.levels, self.pricing, self.active = levels, pricing, {}
def park(self, v: Vehicle) -> Ticket:
for level in self.levels:
spot = level.find_spot(v)
if spot:
spot.vehicle = v
t = Ticket(v, spot)
self.active[t.id] = t
return t
raise RuntimeError("Otopark dolu")
def leave(self, ticket_id: str) -> float:
t = self.active.pop(ticket_id)
t.spot.vehicle = None
return self.pricing.price(t, datetime.now())4. Tartışmaya açılacak noktalar
- Desenler: ücret için Strategy, araç oluşturma için Factory, boş yer göstergesi için Observer,
ParkingLotiçin (dikkatli) Singleton. - Performans: her katta boyuta göre boş yer kuyrukları (
dict[Size, deque]) tutarak aramayıO(1)'e indirmek. - Eşzamanlılık: birden fazla giriş kapısı aynı yeri vermesin diye yer atamasında kilit veya atomik işlem.
- Genişletme: elektrikli araç şarj yerleri, abonelik fiyatlandırması; Open/Closed prensibine uygun mu?
İlgili OOP & Tasarım Desenleri soruları
- Clean code nedir? Yaygın code smell'ler nelerdir?
- Dependency Injection nedir? IoC container ne işe yarar?
- Strategy deseni nedir? if/else zincirlerini nasıl ortadan kaldırır?
- Observer deseni nedir? Gerçek hayatta nerelerde karşımıza çıkar?
- Factory deseni nedir? Ne zaman kullanılır?
- Singleton deseni nedir? Neden bazen anti-pattern olarak görülür?
Bu konuda başka bir soru biliyor musun?
Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.