Transformar atributos opcionais em coleções vazias para código mais limpo, mais seguro e polimórfico, eliminando o erro de bilhões de dólares
TL;DR: Substitua atributos opcionais anuláveis por coleções vazias para eliminar verificações nulas e alavancar o polimorfismo.
TL;DR: Substitua atributos opcionais anuláveis por coleções vazias para eliminar verificações nulas e alavancar o polimorfismo.
Problemas resolvidos
- Exceções de referência nulas
- Lógica condicional excessiva e IFs
- Erros fracos de manuseio
- Atributos opcionais
- Código de validação complexo
- Polimorfismo
Conteúdo relacionado
Passos
- Identificar atributos opcionais que possam ser coleções
- Substituir objetos exclusivos por coleções vazias
- Remover todas as verificações nulas relacionadas a esses atributos opcionais
- Métodos de atualização para trabalhar com coleções em vez de objetos individuais
Código de amostra
Antes do
public class ShoppingCart {
private List<Item> items = new ArrayList<>();
private Coupon coupon = null;
public void addItem(Item item) {
this.items.add(item);
}
public void redeemCoupon(Coupon coupon) {
this.coupon = coupon;
}
public double total() {
double total = 0;
for (Item item : this.items) {
total += item.getPrice();
}
// This a polluted IF and null check
if (this.coupon != null) {
total -= this.coupon.getDiscount();
}
return total;
}
public boolean hasUnsavedChanges() {
// Explicit null check
return !this.items.isEmpty() || this.coupon != null;
}
public boolean hasCoupon() {
return this.coupon != null;
}
}
public class ShoppingCart {
private final List<Item> items = new ArrayList<>();
// This version uses Optionals
// Not all programming languages support this feature
private Optional<Coupon> coupon = Optional.empty();
public void addItem(Item item) {
items.add(item);
}
public void redeemCoupon(Coupon coupon) {
// You need to understand how optionals work
this.coupon = Optional.ofNullable(coupon);
}
public boolean hasUnsavedChanges() {
return !items.isEmpty() || !coupon.isPresent();
}
public boolean hasCoupon() {
return coupon.isPresent();
}
}
Depois disso 🙂
public class ShoppingCart {
private List<Item> items = new ArrayList<>();
// 1. Identify nullable optional attributes
// that could be collections
// 2. Replace single nullable objects with empty collections
private List<Coupon> coupons = new ArrayList<>();
public void addItem(Item item) {
this.items.add(item);
}
// Step 4: Work with collection
// instead of single nullable object
public void redeemCoupon(Coupon coupon) {
this.coupons.add(coupon);
}
// Step 4: Simplified logic without null checks
public double total() {
double total = 0;
for (Item item : this.items) {
total += item.getPrice();
}
// 3. Remove all null checks
// related to these optional attributes
for (Coupon coupon : this.coupons) {
total -= coupon.getDiscount();
}
return total;
}
// Consistent behavior with empty collections
public boolean hasUnsavedChanges() {
// 4. Update methods to work with collections
// instead of single objects
return !this.items.isEmpty() || !this.coupons.isEmpty();
}
// 3. Remove all null checks
// related to these optional attributes
// Collection-based check instead of null check
public boolean hasCoupon() {
return !this.coupons.isEmpty();
}
}
Tipo
- [x] Semiautomático
Segurança ️
Este refactoring é geralmente seguro quando você controla todos os pontos de acesso aos atributos da coleção.
Você precisa certificar-se de que nenhum código externo espera valores nulos e lidar com as APIs internas.
O refactoring mantém o mesmo comportamento externo enquanto simplifica a lógica interna.
Você deve verificar se todos os construtores e métodos de fábrica iniciam as coleções corretamente.
Por que o código é melhor?
O código refactorizado eliminaExceções de ponto zeroReduzindo a complexidade condicional.
Coleções vazias e coleções não vazias se comportam polimórficamente, permitindo que você as trate uniformemente.
O código torna-se mais previsível porque as coleções sempre existem (pelo menos vazias) e respondem às mesmas operações.
Implementações de métodos tornam-se mais curtas e mais focadas na lógica de negócios em vez de manipulação nula.
A abordagem está alinhada com o princípio de tornar os estados ilegais não representáveis em seu modelo de domínio, levando a um código mais robusto e mantido.
Coleções vazias e coleções não vaziaspolymorphic.
Como melhorar a qualidade de vida? ️
No mundo real, contêineres existem mesmo quando estão vazios.
Ao representar coleções opcionais como coleções vazias em vez de nulas, você cria um modelo de realidade mais preciso.
O zero não existe no mundo real, e sempre quebra oBijeção.
Isso mantém a correspondência one-to-one entre conceitos do mundo real e seu modelo computacional, criando uma boaMapa.
Quando você devolve uma coleção em vez de nulls, você também reduzConexão.
Limitações ️
Este refactoring pode não ser adequado quando null tem um significado semântico diferente de "vazio".Algumas APIs legadas podem esperar valores null, exigindo camadas de adaptação.
Você precisa garantir que todos os caminhos de código iniciem coleções consistentemente para evitar estados nulos e vazios misturados.
Refactor com AI
Prompt sugerido: 1. Identificar atributos opcionais revogáveis que poderiam ser coleções 2. Substituir objetos individuais revogáveis por coleções vazias 3. Remover todos os controles nulos relacionados a esses atributos opcionais 4. Atualizar métodos para trabalhar com coleções em vez de objetos individuais 5. Teste que coleções vazias e não-vazias se comportam de forma consistente
Prompt sugerido: 1. Identificar atributos opcionais revogáveis que poderiam ser coleções 2. Substituir objetos individuais revogáveis por coleções vazias 3. Remover todos os controles nulos relacionados a esses atributos opcionais 4. Atualizar métodos para trabalhar com coleções em vez de objetos individuais 5. Teste que coleções vazias e não-vazias se comportam de forma consistente
Without Proper Instructions |
With Specific Instructions |
---|---|
Dias ️
- zero
Nível
- [x] Intermediário
Reações Relacionadas
Veja também
Crédito
Este artigo faz parte da série Refactoring.