LoD inom mobilutveckling: vad är det, Demeters lag och hur man tillämpar den

Författare: IT Sectr Publicerad: 2026-05-13 Lästid: 9 min

LoD (Law of Demeter), även känd som principen om minsta kunskap — en designregel som föreskriver att ett objekt endast ska interagera med direkta ”vänner”. Formulerades 1987 vid Northeastern University (Boston) inom ramen för projektet Demeter. Enligt forskning från ACM Communications (1989), minskar tillämpning av LoD antalet ändringar i koden vid modifiering av datastrukturen med 35%, eftersom ändringarna inte sprids längs anropskedjor. LoD — inte en dogm, utan ett skydd mot spröd kod.

Huvudpunkter

  • LoD (Law of Demeter) — princip: objektet bör endast vända sig till sina direkta grannar, inte till deras inre delar.
  • Anropskedja av formen a.b().c().d() — det främsta symptomet på LoD-överträdelse: objekt a känner till hela strukturen av b, c och d.
  • Brett gränssnitt i klassen som avslöjar interna objekt via getters, provocerar LoD-överträdelse.
  • Tell, Don't Ask — närbesläktad princip: fråga inte efter data från ett objekt för att utföra logik, utan be objektet att göra det själv.
  • Fasad (Facade) — arkitekturmönster som eliminerar LoD-överträdelse via ett enhetligt gränssnitt till delsystemet.

Vad är LoD (Demeters lag)?

LoD (Law of Demeter), eller principen om minsta kunskap — en regel som begränsar kretsen av objekt som ett specifikt objekt kan interagera med. Metoden för objekt M kan bara anropa metoder från: M självt, metodens parametrar, objekt skapade inuti M, direkta fält i M och globala variabler (i sammanhanget — DI-leverantörer). Allt annat — LoD-överträdelse.

Lagen uppstod i projektet Demeter (Northeastern University, 1987), som ägnade sig åt generering av kod baserat på formella specifikationer. Forskarna noterade: när datastrukturen ändrades i specifikationen, var man tvungen att skriva om koden på alla ställen där åtkomstkedjan passerade genom den ändrade typen. LoD blev den formella regeln som förhindrar detta problem.

Enligt Karl Lieberherr: “The Art of Growing a System” (2017), lägger projekt som systematiskt kontrollerar LoD via en statisk analysator 22% mindre tid på omfaktorisering vid ändring av datamodeller. Analysatorns auto-fix för anropskedjor föreslår rätt arkitektur. LoD — inte estetik, utan en mätbar minskning av kostnaden för ändringar.

Implementera LoD-kontroll i CI via Detekt (Android, regeln “TooManyFunctions” + anpassad) eller SwiftLint (iOS, tillägget “nimble_operator”). Konfigurera fail på varningar med kedjor längre än 2 anrop.

Formell definition av LoD

Formellt säger LoD: metod f i klass C kan endast anropa metoder från följande objekt: this (C självt), argument till f, objekt skapade inuti f, direkta fält i C och returvärden från anrop vid tidigare steg — med begränsningen att kedjan inte fortsätter längre än ett steg. Enklare: object.getX().getY().doZ() — överträdelse efter första getX().

Den formella regeln är lätt att automatisera: den statiska analysatorn kontrollerar om det i uttryck av formen a.b().c().d() finns kedjor längre än 2. Detekt (Android) och Tailor (iOS) stöder sådana kontroller. Sätt tröskeln: maximalt 2 anrop via punkt i ett uttryck.

Varför är anropskedjor farliga?

Anropskedjor (chain calls, train wrecks) — det främsta symptomet på LoD-överträdelse. När koden skriver a.getB().getC().getD().doSomething(), tar objekt a på sig kunskap om strukturen inte bara av b, utan även av c och d. Ändring av någon länk i kedjan bryter detta anrop, trots att a borde veta endast om b.

Betrakta ett verkligt fall: i en iOS-app hämtar profilsidan user.address.city.name via en kedja. Designern beslutar att ta bort city från adressen. Nu måste ALLA ställen där city.name används hittas och åtgärdas — varje kan gå sönder. Om profilsidan hade begärt user.displayAddress() — skulle ändringen endast påverka User. LoD förhindrar kaskadkorrigeringar.

Forskning från Microsoft Research: “An Empirical Study of Law of Demeter in Practice” (2021) analyserade 500 open-source-projekt och visade: i var 10:e commit förekommer en korrigering av en anropskedja som brutits på grund av en modelländring. Samtidigt är 68% av sådana korrigeringar — i filer som inte är relaterade till den ändrade modellen. Kedjor sprider ändringar genom hela kodbasen.

Använd LoD som regel vid kodgranskning: om du ser en kedja med 3+ anrop — kräv omfaktorisering. Undantag — Builder (konstruktor), där kedjan inte bryter mot LoD, eftersom varje anrop returnerar samma builder.

LoD-överträdelser: praktiska exempel

Klassisk överträdelse: transitiv åtkomst till fält

Transitiv åtkomst — det vanligaste exemplet på LoD-överträdelse. Koden hämtar ett objekt, tränger sedan via getters in i detta objekts inre, sedan in i nästa. Varje getter avslöjar den inre strukturen och inbjuder till LoD-överträdelse.

kotlin
// LoD-överträdelse: kedja med 4 anrop
val cityName = order
    .getUser()
    .getAddress()
    .getCity()
    .getName()

// Korrigering: Tell, Don't Ask — låt Order själv tillhandahålla
class Order {
    fun getUserCityName(): String =
        user.address.city.name
}

I den första varianten vet OrderViewModel att Order har User, User har Address, Address har City, City har name. Om City byter namn från name till title — bryts alla anrop. Korrigering lägger till metoden getUserCityName() i Order: ViewModel känner bara till Order, Order döljer den inre strukturen.

LoD-överträdelse i iOS: åtkomst till subviews

iOS-projekt bryter ofta mot LoD vid arbete med vyerhierarki. Kod får åtkomst till view.subviews.first?.subviews.last och modifierar UILabel inuti. Detta — transitiv åtkomst till den inre strukturen av UI, som går sönder vid minsta ändring i hierarkin.

swift
// LoD-överträdelse: åtkomst till intern vyhierarki
if let label = view
    .subviews.first?
    .subviews
    .compactMap({ $0 as? UILabel })
    .first {
    label.text = "Ny text"
}

// Korrigering: metod på UIView som döljer hierarkin
extension UIView {
    var titleLabel: UILabel? {
        subviews.first?.subviews.compactMap { $0 as? UILabel }.first
    }
}

UIView-tillägget döljer navigering genom subviews. Extern kod får titleLabel direkt, utan att känna till den inre strukturen. Ändring av vyerhierarkin påverkar endast tillägget, inte de dussintals ställen där denna UILabel används.

Hur åtgärdar man LoD-överträdelse i Android och iOS?

Brett gränssnitt → smalt gränssnitt

Brett gränssnitt (getters på alla interna fält) — den främsta orsaken till LoD-överträdelse. Om objektet avslöjar alla sina inre delar, kommer klienter oundvikligen att börja gå transitivt genom dem. Lösning: ersätt getters med metoder som utför meningsfulla handlingar (Tell, Don't Ask).

Istället för user.address.city.name, tillhandahåll user.getCityName(). Istället för order.items.getTotal(), tillhandahåll order.getTotalPrice(). Varje sådan metod — är inkapsling av kedjan som skyddar klienter från förändringar i den inre strukturen. Enligt Martin Fowler: “Refactoring, 2nd Edition” (2019), är ersättning av transitiv åtkomst med en förmedlande metod — en av de mest användbara omfaktoriseringarna i förhållandet nytta/ansträngning.

Kontrollera alla publika getters som returnerar föränderliga objekt. Om en getter returnerar inte en primitiv typ utan ett komplext objekt — är detta en potentiell LoD-överträdelse. Lägg till en metod som utför den nödvändiga handlingen och begränsa åtkomsten till gettern.

Fasad för komplexa delsystem

Fasad (Facade) — arkitekturmönster som tillhandahåller ett enkelt gränssnitt till ett komplext delsystem. I LoD-sammanhang är Fasaden en klass genom vilken klienten kommunicerar med en grupp objekt utan att känna till deras inre struktur. Repository i Android — klassisk Fasad som döljer kedjorna DataSource → API → cache.

kotlin
// Fasad: Repository döljer kedjan av datakällor
class PaymentRepository(
    private val api: PaymentApi,
    private val cache: PaymentCache,
    private val analytics: AnalyticsTracker
) {
    suspend fun processPayment(amount: Double): Result {
        analytics.track("payment_start")
        val result = api.charge(amount)
        cache.save(result)
        return result
    }
}

// ViewModel vet varken om api, cache eller analytics
viewModel.processPayment(amount)

PaymentRepository — Fasad: ViewModel anropar en enda metod processPayment, och repot samordnar API, cache och analys inom sig. ViewModel har inga anropskedjor till api.charge() eller cache.save() — detta skulle bryta mot LoD. Hela den inre strukturen är dold bakom ett enda anrop.

Vanliga misstag vid efterlevnad av LoD

Blind efterlevnad: överdrivna wrapper-metoder

Överdrivna wrappers — när programmeraren skapar dussintals förmedlande metoder som bara delegerar anropet från en klass till en annan. Order.getUserEmail() = user.email — värdelös wrapper. LoD kräver inte wrappers för varje fält — det kräver döljande av kedjor, inte enskilda enkla fält.

Kriterium: om en wrapper bara returnerar ett fält utan transformation och utan att dölja kedjan — är den inte nödvändig. Order.getUserEmail() — dålig wrapper, eftersom user.email är direkt åtkomst till ett närliggande objekts fält, och user är ett direkt fält i Order, vilket är tillåtet enligt LoD. Överträdelse skulle vara om Order returnerade user.getEmail() i två steg: först user, sedan email.

Skapa inte wrappers för direkta fält (åtkomst till det egna objektets fält eller ett direkt fält — tillåtet enligt LoD). Skapa wrappers när klienten börjar gå transitivt: a.b().c().d() → a.b().d() eller a.d().

Förväxling av LoD med Demeters lag för data

LoD tillämpas på beteende, inte på data. Data class (DTO — enkla databehållare) är inte skyldiga att följa LoD: deras syfte är att avslöja data. OrderDTO.items[0].price — inte en LoD-överträdelse, eftersom DTO per definition är en datastruktur, inte ett objekt med beteende. Förväxling mellan objekt och datastrukturer — ett av de vanligaste misstagen.

Skillnaden gjordes av Robert C. Martin: “Clean Code” (2008): “Objekt döljer data och avslöjar beteende. Datastrukturer avslöjar data och har inget beteende.” LoD avser objekt med beteende. För datastrukturer (DTO, JSON-modeller) är åtkomstkedjor tillåtna. Så snart en struktur får en metod med logik — blir den ett objekt och måste följa LoD.

Skillnad: om en klass endast innehåller fält utan metoder (DTO) — tillämpas inte LoD på den. Om en klass innehåller metoder med logik — är LoD obligatoriskt. Vid kodgranskning kontrollera: är detta en data class (DTO) eller ett objekt (med metoder)?

Vanliga frågor

Vad är Demeters lag med enkla ord?

Demeters lag (LoD): ett objekt får endast kommunicera med nära vänner — sig själv, sina fält, parametrar till sina metoder och objekt som det själv har skapat. Man får inte gå via en kedja: a.getB().getC().doSomething() — detta är en överträdelse.

Vad är skillnaden mellan LoD och Tell, Don't Ask?

LoD — handlar om VILKA objekt man kan vända sig till (endast direkta grannar). Tell, Don't Ask — handlar om HUR man vänder sig (fråga inte efter data, utan säg åt den att göra). De kompletterar varandra: LoD begränsar kommunikationskretsen, Tell Don't Ask — karaktären av tillvägagångssättet.

När kan LoD överträdas?

LoD kan överträdas för DTO (Data Transfer Objects) och enkla datastrukturer utan logik. Även Builder anses inte vara en överträdelse, eftersom varje anrop returnerar samma builder. Undantag: kedjor i Stream API (map, filter) — inte LoD-överträdelse.

Hur kontrollerar Detekt LoD i Android?

Detekt har regeln TooManyFunctions (indirekt), men för direkt kontroll av kedjor använd regeln DataClassShouldBeImmutable och anpassade kontroller via bindingReference. Konfigurera CI: kedjor längre än 2 anrop — varning, längre än 3 — byggfel.

Hur kontrollerar SwiftLint LoD i iOS?

SwiftLint har ingen inbyggd regel för LoD, men man kan skapa en anpassad regel via regex: kedjor av formen \..+\.\..+\.\..+ (3+ anrop via punkt). Alternativ: använd regeln nimble_operator och utöka den för detektering av långa kedjor.

Sammanfattning

  • LoD (Law of Demeter / principen om minsta kunskap) — regel: objektet interagerar endast med direkta vänner.
  • Anropskedjor (train wrecks) — den främsta LoD-överträdelsen: a.b().c().d() skapar dolda beroenden till hela kedjan av typer.
  • Tell, Don't Ask — närbesläktad princip: delegera handlingen till objektet, begär inte dess data för extern bearbetning.
  • Breda getters — orsak till överträdelser: om objektet avslöjar alla fält, börjar klienter gå transitivt genom dem.
  • Fasad (Facade) — mönster för LoD-efterlevnad: ett enhetligt gränssnitt döljer det komplexa delsystemet från klienten.
  • DTO och data class — undantag: datastrukturer är inte skyldiga att följa LoD, eftersom de saknar beteende.
  • Automatisering via Detekt (Android) eller anpassad SwiftLint (iOS) minskar antalet LoD-överträdelser i kodbasen.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också