Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
49m 41s
Herança e interfaces são partes integrantes da programação orientada a objetos (POO). Tim Corey, em seu vídeo " Herança vs. Interfaces em C#: Programação Orientada a Objetos ", oferece uma explicação detalhada sobre quando usar herança e quando optar por interfaces.
Este artigo serve como um guia abrangente para o vídeo de Tim Corey. Este guia detalha os principais conceitos, exemplos e explicações de código apresentados no vídeo, destacando as diferenças entre herança e interfaces e quando usar cada uma.
Tim, em (0:00), começa destacando a importância de distinguir entre herança e interfaces. Ele enfatiza a necessidade de compreender quando usar cada conceito para alcançar os melhores resultados. Seu objetivo é demonstrar isso por meio de exemplos, começando com o uso incorreto da herança simples e, em seguida, corrigindo-o.
Em (1:08), Tim cria um aplicativo de console simples usando .NET 5. Ele nomeia o projeto de "OODemoApp" e explica que o objetivo principal é demonstrar os conceitos em vez de criar código pronto para produção.
Tim em (1:55) aprofunda-se nos princípios básicos da herança. Ele define herança como um mecanismo no qual as propriedades e os métodos de uma classe base são herdados por uma classe derivada. Ele enfatiza que a herança não deve ser usada meramente para reutilização e compartilhamento de código, mas para estabelecer uma relação lógica de "é um/uma".
Pontos principais:
Tim em (7:52) cria uma classe RentalCar para ilustrar o conceito fundamental de herança. Esta categoria representa um carro alugado em uma locadora de veículos em Miami, Flórida.
public class RentalCar
{
public int RentalId { get; set; }
public string CurrentRenter { get; set; }
public decimal PricePerDay { get; set; }
public int NumberOfPassengers { get; set; }
public void StartEngine()
{
Console.WriteLine("Turn key to ignition setting");
Console.WriteLine("Turn key to on");
}
public void StopEngine()
{
Console.WriteLine("Turn key to off");
}
}Public Class RentalCar
Public Property RentalId As Integer
Public Property CurrentRenter As String
Public Property PricePerDay As Decimal
Public Property NumberOfPassengers As Integer
Public Sub StartEngine()
Console.WriteLine("Turn key to ignition setting")
Console.WriteLine("Turn key to on")
End Sub
Public Sub StopEngine()
Console.WriteLine("Turn key to off")
End Sub
End ClassTim, às 10h15, explica como o uso inadequado da herança pode levar a problemas. Ele destaca que, se a herança for mal utilizada, pode levar a um código difícil de gerenciar e estender. Ele desaconselha o uso de herança apenas para compartilhar código.
Tim, às 10h45, adiciona uma enumeração para tipos de carros. Ele cria um novo arquivo de classe chamado Enums.cs para manter todos os enums em um só lugar. Esta enumeração ajudará a diferenciar entre os diferentes estilos de carros.
// Enums.cs
public enum CarType
{
Hatchback,
Sedan,
Compact
}' Enums.vb
Public Enum CarType
Hatchback
Sedan
Compact
End EnumEm seguida, ele adiciona uma propriedade à classe RentalCar para especificar o tipo de carro.
public class RentalCar : RentalVehicle
{
public CarType Style { get; set; }
// Other properties and methods
}Public Class RentalCar
Inherits RentalVehicle
Public Property Style As CarType
' Other properties and methods
End ClassComo Tim explica em (12:27), a agência de aluguel decide adicionar caminhões à sua frota, o que introduz novos requisitos. Ele cria uma classe RentalTruck que herda da classe pai RentalVehicle.
public class RentalTruck : RentalVehicle
{
public TruckType Style { get; set; }
// Other properties and methods
}Public Class RentalTruck
Inherits RentalVehicle
Public Property Style As TruckType
' Other properties and methods
End ClassEm seguida, ele define um novo enum para tipos de caminhão.
// Enums.cs
public enum TruckType
{
ShortBed,
LongBed
}' Enums.vb
Public Enum TruckType
ShortBed
LongBed
End EnumTim em (15:28) enfatiza que só porque duas propriedades compartilham o mesmo nome não significa que elas sejam iguais. Ele ilustra isso com a propriedade Style, que poderia significar diferentes enums (CarType para carros e TruckType para caminhões).
A agência de aluguel amplia sua frota para incluir barcos. Tim demonstra como lidar com isso criando uma classe RentalBoat. Inicialmente, parece administrável, já que os barcos podem compartilhar algumas propriedades com carros e caminhões.
public class RentalBoat : RentalVehicle
{
// Properties and methods specific to boats
}Public Class RentalBoat
Inherits RentalVehicle
' Properties and methods specific to boats
End ClassA introdução de barcos à vela representa um desafio, uma vez que estes não possuem motores. Tim em (19:57) ilustra as limitações da herança neste cenário.
public class RentalSailboat : RentalVehicle
{
public override void StartEngine()
{
throw new NotImplementedException("I do not have an engine to start");
}
public override void StopEngine()
{
throw new NotImplementedException("I do not have an engine to stop");
}
}Public Class RentalSailboat
Inherits RentalVehicle
Public Overrides Sub StartEngine()
Throw New NotImplementedException("I do not have an engine to start")
End Sub
Public Overrides Sub StopEngine()
Throw New NotImplementedException("I do not have an engine to stop")
End Sub
End ClassTim sugere tornar os métodos StartEngine e StopEngine virtuais na classe base para permitir a sobrescrita em classes derivadas que não utilizam esses métodos.
public abstract class RentalVehicle
{
// Common properties
public virtual void StartEngine()
{
Console.WriteLine("Engine started");
}
public virtual void StopEngine()
{
Console.WriteLine("Engine stopped");
}
}Public MustInherit Class RentalVehicle
' Common properties
Public Overridable Sub StartEngine()
Console.WriteLine("Engine started")
End Sub
Public Overridable Sub StopEngine()
Console.WriteLine("Engine stopped")
End Sub
End ClassTim em (21:56) explica as armadilhas de ter métodos em classes herdadas que não deveriam ser chamados. Por exemplo, a classe RentalSailboat, que não possui motor, herda os métodos StartEngine e StopEngine da classe RentalVehicle. Essa situação pode causar problemas se esses métodos forem chamados involuntariamente, pois eles precisam lançar exceções para indicar que não são aplicáveis.
public class RentalSailboat : RentalVehicle
{
public override void StartEngine()
{
throw new NotImplementedException("I do not have an engine to start");
}
public override void StopEngine()
{
throw new NotImplementedException("I do not have an engine to stop");
}
}Public Class RentalSailboat
Inherits RentalVehicle
Public Overrides Sub StartEngine()
Throw New NotImplementedException("I do not have an engine to start")
End Sub
Public Overrides Sub StopEngine()
Throw New NotImplementedException("I do not have an engine to stop")
End Sub
End ClassTim em (24:06) enfatiza como a herança pode levar a uma base de código complexa e confusa quando deixa de fazer sentido lógico. Por exemplo, um veleiro não deve ser tratado como um veículo de aluguel com motor. Isso demonstra as limitações da herança e a necessidade de uma abordagem de projeto melhor.
Para solucionar esses problemas, Tim sugere um design melhor utilizando interfaces. Ele começa criando um novo projeto de aplicativo de console chamado "BetterOODemo" para demonstrar a abordagem aprimorada.
Tim apresenta a interface IRental para englobar propriedades comuns a todos os aluguéis.
public interface IRental
{
int RentalId { get; set; }
string CurrentRenter { get; set; }
decimal PricePerDay { get; set; }
}Public Interface IRental
Property RentalId As Integer
Property CurrentRenter As String
Property PricePerDay As Decimal
End InterfaceTim então cria uma classe base para veículos terrestres, separando o conceito de aluguel de veículos do próprio veículo.
public abstract class LandVehicle
{
public int NumberOfPassengers { get; set; }
public virtual void StartEngine()
{
Console.WriteLine("Engine started");
}
public virtual void StopEngine()
{
Console.WriteLine("Engine stopped");
}
}Public MustInherit Class LandVehicle
Public Property NumberOfPassengers As Integer
Public Overridable Sub StartEngine()
Console.WriteLine("Engine started")
End Sub
Public Overridable Sub StopEngine()
Console.WriteLine("Engine stopped")
End Sub
End ClassAo renomear a classe base do veículo para LandVehicle, Tim garante que apenas os veículos apropriados herdem os métodos relacionados ao motor.
Tim cria classes Car e Truck que herdam de LandVehicle e implementam a interface IRental.
public class Car : LandVehicle, IRental
{
public int RentalId { get; set; }
public string CurrentRenter { get; set; }
public decimal PricePerDay { get; set; }
public CarType Style { get; set; }
}
public class Truck : LandVehicle, IRental
{
public int RentalId { get; set; }
public string CurrentRenter { get; set; }
public decimal PricePerDay { get; set; }
public TruckType Style { get; set; }
}Public Class Car
Inherits LandVehicle
Implements IRental
Public Property RentalId As Integer Implements IRental.RentalId
Public Property CurrentRenter As String Implements IRental.CurrentRenter
Public Property PricePerDay As Decimal Implements IRental.PricePerDay
Public Property Style As CarType
End Class
Public Class Truck
Inherits LandVehicle
Implements IRental
Public Property RentalId As Integer Implements IRental.RentalId
Public Property CurrentRenter As String Implements IRental.CurrentRenter
Public Property PricePerDay As Decimal Implements IRental.PricePerDay
Public Property Style As TruckType
End ClassEste design mantém uma clara separação de responsabilidades, garantindo que cada classe possua apenas propriedades e métodos relevantes ao seu tipo.
Tim em (31:41) discute a importância de evitar duplicação desnecessária de código. Ele explica que, embora a interface IRental exija as mesmas propriedades em várias classes, isso não é considerado uma violação do princípio DRY (Don't Repeat Yourself - Não se Repita), pois nenhuma lógica é duplicada - apenas declarações de propriedade.
Tim em (35:09) explica como lidar com a classe RentalSailboat separadamente implementando a interface IRental, em vez de herdar de LandVehicle. Essa abordagem ajuda a evitar as armadilhas associadas à herança inadequada.
public class Sailboat : IRental
{
public int RentalId { get; set; }
public string CurrentRenter { get; set; }
public decimal PricePerDay { get; set; }
// Additional properties and methods specific to sailboats
}Public Class Sailboat
Implements IRental
Public Property RentalId As Integer
Public Property CurrentRenter As String
Public Property PricePerDay As Decimal
' Additional properties and methods specific to sailboats
End ClassTim cria uma lista para gerenciar diferentes tipos de aluguéis, utilizando a interface IRental para armazenar vários tipos de itens, incluindo caminhões, veleiros e carros.
List<IRental> rentals = new List<IRental>
{
new Truck { CurrentRenter = "Truck Renter" },
new Sailboat { CurrentRenter = "Sailboat Renter" },
new Car { CurrentRenter = "Car Renter" }
};Dim rentals As New List(Of IRental) From {
New Truck With {.CurrentRenter = "Truck Renter"},
New Sailboat With {.CurrentRenter = "Sailboat Renter"},
New Car With {.CurrentRenter = "Car Renter"}
}Este design permite percorrer os aluguéis e acessar propriedades comuns como CurrentRenter, PricePerDay, e RentalId.
foreach (var rental in rentals)
{
Console.WriteLine($"Renter: {rental.CurrentRenter}, Price Per Day: {rental.PricePerDay}");
}For Each rental In rentals
Console.WriteLine($"Renter: {rental.CurrentRenter}, Price Per Day: {rental.PricePerDay}")
NextPara acessar propriedades e métodos específicos de diferentes tipos de aluguel, Tim demonstra como usar a palavra-chave is para verificar e converter objetos para seus tipos respectivos.
foreach (var rental in rentals)
{
if (rental is Truck truck)
{
Console.WriteLine($"Truck Style: {truck.Style}, Passengers: {truck.NumberOfPassengers}");
}
else if (rental is Sailboat sailboat)
{
// Access sailboat-specific properties
}
else if (rental is Car car)
{
// Access car-specific properties
}
}For Each rental In rentals
If TypeOf rental Is Truck Then
Dim truck As Truck = CType(rental, Truck)
Console.WriteLine($"Truck Style: {truck.Style}, Passengers: {truck.NumberOfPassengers}")
ElseIf TypeOf rental Is Sailboat Then
Dim sailboat As Sailboat = CType(rental, Sailboat)
' Access sailboat-specific properties
ElseIf TypeOf rental Is Car Then
Dim car As Car = CType(rental, Car)
' Access car-specific properties
End If
NextTim enfatiza que o uso de interfaces proporciona flexibilidade para mudanças futuras. Por exemplo, adicionar novos tipos de itens para alugar, como tanques ou televisores, não afetaria a estrutura existente.
Tim desaconselha o uso excessivo de herança para compartilhamento de código, pois isso pode levar a uma base de código complexa e inflexível. Em vez disso, ele recomenda aproveitar as interfaces e a composição para alcançar os resultados desejados sem estender a relação "é um/uma" além de seus limites lógicos.
A explicação de Tim Corey sobre herança e interfaces em Programação Orientada a Objetos oferece um caminho claro para a criação de código flexível e de fácil manutenção. Ao destacar as armadilhas comuns e fornecer um design refinado com interfaces, ele garante que os desenvolvedores possam tomar decisões informadas sobre a estruturação eficaz de seus aplicativos.
Para uma análise mais aprofundada desses conceitos e para vê-los em ação, assista ao vídeo completo de Tim. O canal dele é uma mina de ouro de tutoriais de programação. Não perca esta oportunidade!
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy