这种调用函数的方式不好吗?


10

我有以下代码:

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);
}

我认为通过这种方式,例如,我消除了了解LatLng另一门课中的内容的责任。

而且,您无需在调用函数之前准备数据。

你怎么看?

这种方法有名称吗?真的是不好的做法吗?


2
我认为您只是使用该语言的内置方法重载来处理封装。这不是好/坏。只是一个可以帮助或伤害您的代码的工具。
bitoflogic

5
如果您的目标是向LatLng此类客户隐瞒Camera,那么您可能不希望moveCameraTo(LatLng)成为public
bitoflogic

除了答案中给出的建议外,这也是提及YAGNI的好地方。您将不需要它。在有一个好的用例之前,请不要定义API方法,因为……您将不需要它。
Patrick Hughes

没有错,moveCameraToLocationmoveCameraTo/ moveCameraToCoords。绝对不希望以相同的名称传递Location / lat / long。
Insidesin

Answers:


9

您正在使用语言方法重载功能为调用方提供解决方法对位置信息的依赖性的替代方法。然后,您将委托另一种方法来解决剩余的更新相机工作。

如果您只是继续扩展方法调用方法的链,那么这里的代码味道将是。Location拍摄方法调用double拍摄方法,double拍摄方法调用latLng拍摄方法,该方法最终调用知道如何更新相机的内容。

长链只有最薄弱的一环才有力。链的每个扩展都增加了必须工作的代码的覆盖范围,否则此事情将中断。

如果每种方法都采用最短的路径来解决所提出的问题,那将是一个更好的设计。这并不意味着每个人都必须知道如何更新相机。每个人都应将其位置参数类型转换为一种统一的类型,该类型可以传递给在知道这种类型时会知道如何更新相机的东西。

那样做,您就可以删除其中一个,而不会破坏其他所有内容的一半。

考虑:

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

这使得处理纬度和经度LatLng问题。代价是它传播了LatLng周围的知识。这看起来可能很昂贵,但是根据我的经验,它是原始痴迷的一种更好的替代选择,这是避免建立参数对象的原因

如果Location可以重构但LatLng不能重构,请考虑通过在以下工厂添加工厂来解决此问题Location

moveCameraTo( location.ToLatLng() );

这也很好地避免了原始的困扰。


1
对我来说似乎并不那么糟糕-但这实际上只是为消费者带来便利。如果将其链接10次,或者消费者实际上并不需要所有这些选项,那么我将其称为代码气味。
mcknz

1
但是,在每个函数中,将所有转换双精度逻辑转换为LagLng或Location转换为LagLng的替代方案是什么?
Tlaloc-ES

@ Tlaloc-ES更好吗?
candied_orange

@ Tlaloc-ES当将原语加载到域逻辑中时,“转换”仅需要发生一次。反序列化DTO时会发生这种情况。然后,所有的域逻辑得到以绕过LatLngLocation对象。您可以使用New LatLng(Location)Location.toLatLng()如果需要从一个转到另一个来显示两者之间的关系。
bitoflogic

1
@ Tlaloc-ES相关阅读:Martin Fowler的FlagArgument。阅读“缠结的实现”部分。
Marc.2377 '19

8

您的解决方案没有什么特别的错误。

但是我个人的喜好是那些方法没有那么有用。并且只需将它们分离的任何对象的接口复杂化即可。

void moveCameraTo(double latitude, double longitude)并没有真正简化代码,因为我看不出有什么问题,简单地调用moveCameraTo(new LatLng(latitude, longitude));它的地方。这种方法也散发出原始的迷恋。

void moveCameraTo(Location location)可以通过证明得到更好的解决Location.ToLatLng()方法和调用moveCameraTo(location.ToLatLng())

如果这是C#,并且确实需要这种方法,那么我希望将它们作为扩展方法而不是实例方法。如果您尝试抽象并对该实例进行单元测试,那么扩展方法的使用将变得非常明显。因为仅假冒单个方法而不是通过简单转换实现多个重载会容易得多。

我认为通过这种方式,例如,我消除了了解另一类中的LatLng的责任。

我认为没有任何理由会造成问题。只要您的代码引用包含的类void moveCameraTo(LatLng latLng),它仍然间接依赖于LatLng。即使该类从不直接实例化。

而且,您无需在调用函数之前准备数据。

我不明白你的意思。如果这意味着创建新实例或将类从一个实例转换为另一个实例,那么我认为这没有问题。

考虑一下,我觉得我所说的也得到.NET本身的API设计的支持。从历史上看,许多.NET类都遵循您的方法,即使用不同的参数进行大量重载,并在内部进行简单转换。但这是在扩展方法存在之前。更加现代的.NET类在其自己的API中更轻量,并且如果有任何带有参数重载的方法,它们将作为扩展方法提供。较早的示例是NLog ILogger,它具有数十个用于写入日志的重载。将它与较新的Microsoft.Extensions.Logging.ILogger进行比较,后者总共有3种方法(如果算上日志本身,则只有1种)。但是有很多帮助者和各种参数化方法作为扩展方法

我认为这个答案表明,某些语言将具有使这种设计更好的工具。我对Java不太了解,所以不确定是否会有任何等效的Java。但是即使使用简单的静态方法也可能是一种选择。


不知道为什么,但是尽管有一个竞争者,但我发现自己仍在为这个答案加油。我认为您只是设法使观点变得更好。我唯一的反馈是要记住,并非每个人都在.NET上处理此问题。+1
candied_orange

@candied_orange对。现在,我对OP的问题有了更好的了解,那看起来更像Java,而不是C#。
欣快的

我认为moveCameraTo(new LatLng(latitude, longitude));在项目的任何地方使用都没有问题,但是我认为直接使用moveCametaTo(latLng)更清楚,就像java中的File一样,您可以像字符串一样传递路径,或者像Path类一样传递
Tlaloc-ES

1

我不确定它的专有名称是什么(如果有的话),但这是一个好习惯。您公开了多个重载,从而允许调用类确定要使用的参数集。如您所说,另一个类可能不知道什么是LatLng对象,但是可能知道其对象Location

调用一个方法也很关键,因为您不希望在这些方法之间重复代码。完成后,选择一个方法作为可以完成工作的方法,然后让其他方法(直接或间接)调用它


1

如果您介意使用某种方法,那只是方法重载功能很好。

但是,并没有消除了解什么是LatLng的责任。因为您正在初始化LatLng latLng = new LatLng(latitude, longitude)。这完全依赖LatLng。(要了解为什么初始化是一个依赖关系问题,可以检查“ 依赖关系注入”。)创建重载方法只会帮助那些不在乎的客户LatLng。如果您的意思是这样,那也很好,但是我不认为这是一种方法。对于客户来说,这只是许多服务方法。

因此,设计体系结构有两种选择:

  1. 创建许多重载方法并将其提供给客户端。
  2. 创建一些需要参数作为接口或具体类的重载方法。

我尽量避免创建需要原始类型作为参数的方法(选项1)。因为如果您的业务变化很多,并且您需要播放方法参数,那么更改和实现所有调用程序功能确实很困难。

而不是使用接口(依赖注入)。如果您认为这是成本并且需要更多时间,请使用类并提供其映射器扩展方法(选项2)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.