essa maneira de chamar uma função é uma má prática?


10

Eu tenho o seguinte código:

public void moveCameraTo(Location location){
    moveCameraTo(location.getLatitude(), location.getLongitude());
}

public void moveCameraTo(double latitude, double longitude){
    LatLng latLng = new LatLng(latitude, longitude);
    moveCameraTo(latLng);
}

public void moveCameraTo(LatLng latLng){
    GoogleMap googleMap =  getGoogleMap();
    cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, INITIAL_MAP_ZOOM_LEVEL);
    googleMap.moveCamera(cameraUpdate);
}

Penso que desta maneira elimino a responsabilidade de saber o que é uma LatLngoutra aula, por exemplo.

E você não precisa preparar os dados antes de chamar a função.

O que você acha?

Essa abordagem tem um nome? É realmente uma má prática?


2
Eu acho que você está apenas lidando com o encapsulamento usando a sobrecarga de método interna da linguagem. Não é bom / ruim. Apenas uma ferramenta que pode ajudar ou prejudicar seu código.
bitsoflogic

5
Se seu objetivo é ocultar LatLngos clientes dessa Cameraclasse, provavelmente você não quer moveCameraTo(LatLng)ser public.
bitsoflogic

Além do conselho dado nas respostas, este parece ser um bom lugar para mencionar YAGNI. Você não vai precisar disso. Não defina métodos de API antes de haver um bom caso de uso, porque ... Você não precisará dele.
Patrick Hughes

Nada de errado com moveCameraToLocatione moveCameraTo/ moveCameraToCoords. Definitivamente não gostaria de passar Location / lat / long com os mesmos nomes.
22/02/19

Respostas:


9

Você está usando o recurso de sobrecarga de método de idiomas para oferecer ao chamador formas alternativas de resolver a dependência dos métodos nas informações posicionais. Você está delegando outro método para resolver o trabalho restante de atualização da câmera.

O cheiro do código aqui seria se você continuasse apenas estendendo a cadeia de métodos chamando métodos. O método de tomada de localização chama o método de tomada dupla, que chama o método de latLng, que finalmente chama algo que sabe como atualizar a câmera.

As cadeias longas são tão fortes quanto o elo mais fraco. Cada extensão da cadeia aumenta a área de cobertura do código que precisa funcionar ou essa coisa quebra.

É um design muito melhor se cada método seguir o caminho mais curto possível para solucionar o problema que lhe foi apresentado. Isso não significa que cada um deve saber como atualizar a câmera. Cada um deve converter seu tipo de parâmetro de posição em um tipo uniforme que pode ser passado para algo que sabe como atualizar a câmera quando apresentado esse tipo.

Faça dessa maneira e você poderá remover um sem quebrar metade de todo o resto.

Considerar:

public void moveCameraTo(Location location){
    moveCameraTo( new LatLng(location) );
}

Isso faz com que lidar com LatLngo problema de latitude e longitude . O custo é que ele espalha conhecimento LatLngao redor. Isso pode parecer caro, mas, na minha experiência, é uma alternativa preferível à obsessão primitiva, que é o que evitar o estabelecimento de um objeto de parâmetro o deixa preso.

Se Locationé refatorável, mas LatLngnão é, considere resolver isso adicionando uma fábrica a Location:

moveCameraTo( location.ToLatLng() );

Isso também evita muito bem a obsessão primitiva.


1
Não me parece tão ruim - é realmente apenas uma conveniência para o consumidor. Se isso foi encadeado 10 vezes ou se o consumidor realmente não precisa de todas essas opções, eu chamaria isso de cheiro de código.
Mcknz

1
Mas qual é a alternativa de colocar toda a lógica para transformar dobras para LagLng ou Location para LagLng em cada função?
Tlaloc-ES

@ Tlaloc-ES melhor?
21319 Candied_orange

@ Tlaloc-ES A "transformação" só precisa acontecer uma vez quando as primitivas estão sendo carregadas na lógica do domínio. Isso ocorreria quando você desserializasse o DTO. Então, toda a lógica do seu domínio pode passar por objetos LatLngou Locationobjetos. Você pode mostrar o relacionamento entre os dois com New LatLng(Location)ou Location.toLatLng()se precisar passar de um para o outro.
bitsoflogic

1
@ Tlaloc-ES Leitura relacionada: FlagArgument por Martin Fowler. Leia a seção "Implementação emaranhada".
Marc.2377 22/02/19

8

Não há nada de particularmente errado com sua solução.

Mas minha preferência pessoal seria que esses métodos não sejam tão úteis. E complique a interface de qualquer objeto do qual eles se separem.

O void moveCameraTo(double latitude, double longitude)código não simplifica realmente o código, pois não vejo problema em simplesmente chamá moveCameraTo(new LatLng(latitude, longitude));-lo. Este método também cheira a obsessão primitiva.

Isso void moveCameraTo(Location location)poderia ser melhor resolvido provando Location.ToLatLng()método e chamando moveCameraTo(location.ToLatLng()).

se fosse C # e se esses métodos fossem realmente necessários, eu os preferiria como métodos de extensão em vez de métodos de instância. O uso de métodos de extensão se tornaria realmente óbvio se você tentasse abstrair e testar a unidade nesta instância. Como seria muito mais fácil falsificar um método único, em vez de várias sobrecargas com conversões simples.

Penso que desta maneira elimino a responsabilidade de saber o que é um LatLng em outra classe, por exemplo.

Não vejo razão para que isso seja um problema. Desde que seu código faça referência a classe que contém void moveCameraTo(LatLng latLng), ainda depende indiretamente LatLng. Mesmo que essa classe nunca seja diretamente instanciada.

E você não precisa preparar os dados antes de chamar a função.

Eu não entendo o que você quer dizer. Se isso significa criar uma nova instância ou transformar classes de uma para outra, não vejo problema nisso.

Pensando nisso, sinto que o que estou dizendo também é suportado pelo design de API do próprio .NET. Historicamente, muitas classes do .NET seguiam a abordagem de sobrecargas com parâmetros diferentes e conversões simples. Mas isso foi antes da existência de métodos de extensão. As classes .NET mais modernas são mais leves em suas próprias APIs e, se houver algum método com sobrecarga de parâmetro, elas serão fornecidas como métodos de extensão. Exemplo mais antigo é o NLog ILogger, que possui dezenas de sobrecargas para gravar no log. Compare isso com o Microsoft.Extensions.Logging.ILogger mais recente que possui um total de 3 métodos (e apenas 1 se você contar o próprio log). Mas existem muitos ajudantes e várias parametrizações como métodos de extensão .

Penso que esta resposta mostra que algumas línguas teriam ferramentas para tornar o design mais agradável. Eu não sei muito sobre Java, então não tenho certeza se haveria algum equivalente. Mas mesmo usando métodos estáticos simples pode ser uma opção.


Não sei por que, mas me pego torcendo por essa resposta, apesar de ter uma que é concorrente. Eu acho que você conseguiu explicar melhor. Meu único comentário seria lembrar que nem todos que lidam com esse problema estão no .NET. +1
candied_orange 21/02/19

@candied_orange Certo. Agora que pareço melhor a pergunta do OP, ela se parece mais com Java do que em C #.
eufórico

Eu acho que realmente não tem um problema em uso moveCameraTo(new LatLng(latitude, longitude));em qualquer lugar do projeto, mas acho que é mais claro usar diretamente o moveCametaTo (latLng), é como um arquivo em java, você pode passar como uma string ou como uma classe Path
Tlaloc-ES

1

Não tenho certeza de qual é o nome adequado para isso, se ele tiver um, mas é uma boa prática. Você expõe várias sobrecargas, permitindo que a classe de chamada determine qual conjunto de parâmetros deseja usar. Como você diz, outra classe pode não saber o que é um LatLngobjeto, mas pode conhecer o seu Location.

Ter um método chamando o outro também é fundamental, pois você não deseja código duplicado nesses métodos. Como você fez, escolha um método para ser o que faz o trabalho e faça com que os outros métodos o chamem (direta ou indiretamente)


1

Se você se importa em usar tipos de métodos, é apenas um recurso de sobrecarga de métodos que é bom.

Mas não há como eliminar a responsabilidade de saber o que é um LatLng . Porque você está inicializando LatLng latLng = new LatLng(latitude, longitude). Isso é totalmente dependente de LatLng. (Para entender por que a inicialização é um problema de dependência, você pode verificar a injeção de dependência ) A criação de um método sobrecarregado ajuda apenas os clientes que não se importam LatLng. Se você quer dizer isso, também é bom, mas não acho que seja uma abordagem. São apenas muitos métodos de serviço para clientes.

Portanto, existem duas opções para projetar sua arquitetura:

  1. Crie muitos métodos sobrecarregados e forneça-os ao cliente.
  2. Crie alguns métodos sobrecarregados que precisem de parâmetros como interface ou classe concreta.

Fugo o mais possível, criando métodos que precisam de tipos primitivos como parâmetros (opção 1). Como se sua empresa muda muitas vezes e você precisa reproduzir parâmetros de método, é realmente difícil alterar e implementar todas as funções de quem chama.

Em vez disso, use interfaces (injeção de dependência). Se você acha que custa e leva mais tempo, use as classes e forneça seus métodos de extensão do mapeador (Opção 2).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.