1
resposta

Dúvida sobre o primeiro exemplo do Princípio da substituição de Liskov

No exemplo da aula a classe filha continua recebendo um parâmetro no método que não será mais utilizado pois agora ela retorna um valor fixo ( para os funcionários part-time). Ela apresenta esse comportamento por causa da herança, mas, não é incorreto desenhar seu código daquele modo? Você tem um valor no método que simplesmente não é usado nunca para manter a classe herdando de outra. Isso parece estranho e me deixou em dúvida.

1 resposta

Olá, tudo bem?

Manter um parâmetro em um método que não é utilizado pode parecer estranho e até mesmo incorreto à primeira vista. No exemplo que você mencionou, a classe PartTimeEmployee herda de Employee e o método calculatePay() recebe um parâmetro que não é utilizado, o que viola o Princípio da Substituição de Liskov (LSP).

O LSP nos diz que as subclasses devem ser substituíveis por suas superclasses sem alterar o comportamento do programa. No caso do exemplo da aula, a classe PartTimeEmployee está alterando o comportamento esperado ao ignorar o parâmetro e retornar um valor fixo.

Para resolver esse problema, a aula sugere uma refatoração usando o conceito de composição ao invés de herança direta. O uso de um protocolo PayCalculator permite que diferentes tipos de cálculo de pagamento sejam implementados separadamente e injetados na classe Employee. Dessa forma, a lógica de cálculo de pagamento não precisa ser alterada na subclasse, mantendo o comportamento esperado.

Aqui está um exemplo prático para ilustrar melhor:

protocol PayCalculator {
    func calculatePay(hoursWorked: Double) -> Double
}

class HourlyPayCalculator: PayCalculator {
    var hourlyRate: Double

    init(hourlyRate: Double) {
        self.hourlyRate = hourlyRate
    }

    func calculatePay(hoursWorked: Double) -> Double {
        return hoursWorked * hourlyRate
    }
}

class FixedPayCalculator: PayCalculator {
    var fixedAmount: Double

    init(fixedAmount: Double) {
        self.fixedAmount = fixedAmount
    }

    func calculatePay(hoursWorked: Double) -> Double {
        return fixedAmount
    }
}

class Employee {
    var payCalculator: PayCalculator

    init(payCalculator: PayCalculator) {
        self.payCalculator = payCalculator
    }

    func calculatePay(hoursWorked: Double) -> Double {
        return payCalculator.calculatePay(hoursWorked: hoursWorked)
    }
}

class FullTimeEmployee: Employee {
}

class PartTimeEmployee: Employee {
}

let employees: [Employee] = [
    FullTimeEmployee(payCalculator: HourlyPayCalculator(hourlyRate: 40)),
    PartTimeEmployee(payCalculator: FixedPayCalculator(fixedAmount: 100))
]

employees.forEach { employee in
    print(employee.calculatePay(hoursWorked: 40))
}

Com essa abordagem, a classe Employee pode usar diferentes estratégias de cálculo de pagamento sem precisar alterar o método calculatePay(). Assim, você mantém a conformidade com o LSP e evita parâmetros não utilizados.

Espero ter ajudado. Qualquer dúvida manda aqui. Bons estudos.