• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

3 dicas para melhorar seu código orientado a objetos

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
Introdução


Um dos maiores desejos dos desenvolvedores é escrever um código correto e manutenível. Ao longo dos anos, a comunidade juntou um conjunto de ideias, heurísticas e padrões de solução a problemas recorrentes. Este texto tem como objetivo mostrar algumas dicas para tornar seu código mais testável, claro e coeso.

Lógica sobre o estado de objetos


Digamos que você está escrevendo um sistema de biblioteca e que em determinados momentos é necessário saber o estado de um empréstimo para a execução de determinada lógica. Poderíamos fazer algo do tipo:


if(emprestimo.DataDeDevolução > DateTime.Now)
{
EnviarEmailDeAtraso();
}

Será que teria algum problema nisso? Podemos pensar em alguns:

  1. E se essa lógica for necessária em outras partes do sistema? Pensando nas bases da orientação a objetos, comportamentos devem estar pertos dos dados que utilizam. Logo, a coesão das partes do sistema está prejudicada. Além da repetição de código desnecessária, risco de cometer algum erro como usar um maior ou igual (≥) ao invés de um maior (>).
  2. Como seriam os testes? Por enquanto, não é possível testar esse estado isoladamente, o que pode causar redundância de testes em outras classes. Caso seja uma necessidade, também não é possível testar com outras datas, apenas DateTime.Now.

A partir dessas informações, como poderíamos melhorar esse código? Uma sugestão:


if(emprestimo.ExpiradoEm(DateTime.Now))
{
EnviarEmailDeAtraso();
}

public bool ExpiradoEm(DateTime dateTime)
{
return emprestimo.DataDeDevolução > dateTime;
}

ou até:


public bool Expirou()
{
return emprestimo.DataDeDevolução > DateTime.Now;
}
Lógica sobre o estado de uma lista


Continuando no contexto de empréstimo de livros, digamos que precisamos saber algumas informações sobre os empréstimos de determinado usuário:

  • Quantos empréstimos estão abertos?
  • Quais empréstimos expiram nessa semana?
  • O usuário pegou algum livro com um título específico?

Poderíamos fazer algo semelhante a:


public class Usuario
{
//Essa lista é inicializada no construtor
public List<Emprestimo> Emprestimos;

public Usuario()
{
Emprestimos = new List<Emprestimo>();
}
}

Usuario user = new Usuario();
//Neste momento a lista de empréstimos possui n elementos.

//Quantos empréstimos estão abertos?
int quantidadeDeEmprestimosAbertos =
user
.Emprestimos
.Count(x => !x.Expirou());

//Quais empréstimos expiram nessa semana?
DateTime daquia6dias = DateTime.Now.AddDays(6);
DateTime daquia7dias = DateTime.Now.AddDays(7);
List<Emprestimo> = emprestimosQueExpiramEssaSemana =
user
.Emprestimos
.Where(x => !x.ExpiradoEm(daquia6dias) && x.ExpiradoEm(daquia7dias))
.ToList();

//O usuário pegou algum livro com um título específico?
bool jaPegouEsseLivro =
user
.Emprestimos
.Any(x => string.Equals(x.Titulo, "Refatoração"));

Quais problemas identificamos no código acima? Os mesmos problemas que vimos anteriormente, mas focados em uma coleção. No final das contas, a lista de empréstimos também é tem um sentido coeso pro domínio. Seguindo as ideias já comentadas, uma sugestão de solução seria:


public class TodosEmprestimos
{
private List<Emprestimo> _emprestimos;

public int NumeroDeAbertos()
{
return _emprestimos.Count(x => !x.Expirou());
}

public List<Emprestimo> EmprestimosQueExpiramEm(DateTime expiracao)
{
DateTime umDiaAntesDaExpiracao = expiracao.AddDays(-1);
return _emprestimos
.Where(x => !x.ExpiradoEm(umDiaAntesDaExpiracao) && x.ExpiradoEm(expiracao))
.ToList();
}

public bool PegouLivro(string titulo)
{
bool PegouEsseLivro = _emprestimos.Any(x => string.Equals(x.Titulo, titulo));
}
}
public class Usuario
{
public TodosEmprestimos Emprestimos;

public int NumeroDeEmprestimosAbertos()
{
return Emprestimos.NumeroDeAbertos();
}

public List<Emprestimo> EmprestimosQueExpiramEmUmaSemana()
{
DateTime daquia7dias = DateTime.Now.AddDays(7);
return EmprestimosQueExpiramEm(daquia7dias);
}

public bool PodePegarEsseLivro(string titulo)
{
return !Emprestimos.PegouEsseLivro(titulo);
}
}

Ganhamos coesão, reusabilidade e testabilidade. Outro ponto: se quiséssemos impor uma estrutura de dados específica pra coleção por uma demanda de negócio, o código estaria alinhado as necessidades do mundo real. Por exemplo, se precisássemos que os empréstimos estivessem ordenados pelo tempo, o encapsulamento como uma classe permitiria mais facilmente.

Tipo primitivo com significado para o domínio


A última dica vai mostrar como trazer o domínio para mais perto do código. Muito provavelmente, nosso sistema de biblioteca precisa guardar o CPF do usuário. Como o documento transita pelo sistema? Um campo string na classe usuário? A partir do que já comentamos, quais os prováveis problemas dessa abordagem?


public Usuario
{
public string CPF {get; private set;}
}

Possível resposta: Dificuldade de validação, menos focalização pros testes, menos coesão, etc.

Como podemos melhorar isso? Se criarmos uma classe para representar esse conceito, podemos ter certas vantagens.


public CPF
{
private string cpf;

private CPF(string cpfValido)
{
cpf = cpfValido;
}

public static CPF Create(string cpf)
{
//aqui estaria o algoritmo de validação
if(isValid(cpf))
{
return CPF(cpf);
}

throw new ArgumentException("CPF informado inválido");
}

public string EmTextoLimpo()
{
return cpf;
}
}

public User
{
public CPF cpf {get; set;}
}

Agora com uma classe, podemos fazer diversos testes para o algoritmo aqui nessa classe, a validação está isolada e, por fim, aumentamos a coesão do conceito de CPF. O ponto de atenção a se levar em conta é a facilidade de verificar tal comportamento em tempo de execução com o que a linguagem/framework já disponibiliza, ou seja, se é muito fácil fazer essa verificação usando algum recurso nativo talvez não valha a pena criar um nova classe, cabe a análise.

Conclusão


A programação orientada a objetos nos traz a possibilidade de criar códigos coesos, modulares e encapsulados. Contudo, isso não vem de graça, é necessária a utilização das boas práticas e de uma reflexão se estamos fazendo nosso código OO da melhor forma. Este texto foi inspirado e baseado no módulo de heurísticas para orientação objetos da Jornada Dev+Eficiente. Por fim, avalie se as dicas que passei fazem sentido para seu código. Obrigado!


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу