Design patterns 一个API方法做两件事;这是创建API时的良好实践吗?

Design patterns 一个API方法做两件事;这是创建API时的良好实践吗?,design-patterns,api-design,Design Patterns,Api Design,我的同事和我在服务的设计上有点分歧,我需要社区的帮助来确定正确的做法 上下文:我们正在创建一项服务,允许画家/插图画家在云中存储图像。一组图像构成一个图像包 场景:我们正在尝试添加将艺术家与图像包关联的逻辑。我们目前已经有了一个API,允许我们创建图像包(只不过是一个指向图像的链接,带有名称和描述)。我们没有创建艺术家的API,也没有将艺术家与图像包关联的API 他的视角:在调用createImagePack时添加以下参数[artist\u id、artist\u name、artist\u d

我的同事和我在服务的设计上有点分歧,我需要社区的帮助来确定正确的做法

上下文:我们正在创建一项服务,允许画家/插图画家在云中存储图像。一组图像构成一个图像包

场景:我们正在尝试添加将艺术家与图像包关联的逻辑。我们目前已经有了一个API,允许我们创建图像包(只不过是一个指向图像的链接,带有名称和描述)。我们没有创建艺术家的API,也没有将艺术家与图像包关联的API

他的视角:在调用createImagePack时添加以下参数[artist\u id、artist\u name、artist\u desc]。如果艺术家id为“null”,我们将使用艺术家名称和艺术家描述在系统中创建新的艺术家,并自动将他/她分配给新创建的图像包。然后API将以图像包id和艺术家id进行响应

我的观点:上述方法混合了各种顾虑,增加了管理和更新createImagePack API的风险,并打破了“API应按其名称行事”的一般经验法则。[我们可以将名称更新为createImagePackapiandCreateArtitifArtistidNotNull,但也有一些代码气味]。我们应该将这两个调用分开,使它们成为独立的API,并创建一个门面来支持艺术家和图像的一次性创建

我是不是分析过度了?他们关于什么是最好的行动方针的优秀评论是什么


更新:我们的系统中确实有“用户”的概念,因此另一种方法是创建一个关联表,在其中关联用户id,将id打包到艺术家打包映射表中。这避免了为艺术家创建单独的实体,并将我们与我们的“用户”概念松散地联系在一起,因为我们的“用户”概念没有任何强类型。

我认为将关注点混合在一种方法中不是一个好主意。一种方法应该做一件事(例如createImagePack、CreateArtister、associateImagePack、DeleteArtister等)。然而,您可以做的是将对逻辑相关方法的调用组合成一个方法调用,以使用Façade模式创建复合功能

在façade类中,您将有一个定义如下的方法:

 public Artist createImagePackAndArtist(String artist_name, String artist_desc){        
     ImagePack imagePack = new ImagePack();
     Artist artist = new Artist(artist_name, artist_desc);
     artist.associateImagePack(imagePack);
     return artist;
 }
在这里,您将功能/方法调用组合到一个方法中

从返回的对象艺术家中,您可以调用方法返回艺术家的ImagePack对象,然后从艺术家对象中返回ImagePack_id、艺术家id等

立面的目的是提供方便的方法。您可以创建另一个方法,将新图像包添加到已存在的艺术家

  public void createImagePackForArtist(Artist artist){        
     ImagePack imagePack = new ImagePack();
     if (artist != null) {        
           artist.associateImagePack(imagePack);
     } else {
           // throw ArtistIsNullException
     }
 }
理想情况下,在尝试关联图像包之前,您应该检查艺术家是否存在。这将发生在立面之外


还可以看看工厂模式。您可以实现这一点,而不是自己创建对象。还可以看看单例模式。立面和工厂通常是单体的。

我认为将关注点混合在一种方法中不是一个好主意。一种方法应该做一件事(例如createImagePack、CreateArtister、associateImagePack、DeleteArtister等)。然而,您可以做的是将对逻辑相关方法的调用组合成一个方法调用,以使用Façade模式创建复合功能

在façade类中,您将有一个定义如下的方法:

 public Artist createImagePackAndArtist(String artist_name, String artist_desc){        
     ImagePack imagePack = new ImagePack();
     Artist artist = new Artist(artist_name, artist_desc);
     artist.associateImagePack(imagePack);
     return artist;
 }
在这里,您将功能/方法调用组合到一个方法中

从返回的对象艺术家中,您可以调用方法返回艺术家的ImagePack对象,然后从艺术家对象中返回ImagePack_id、艺术家id等

立面的目的是提供方便的方法。您可以创建另一个方法,将新图像包添加到已存在的艺术家

  public void createImagePackForArtist(Artist artist){        
     ImagePack imagePack = new ImagePack();
     if (artist != null) {        
           artist.associateImagePack(imagePack);
     } else {
           // throw ArtistIsNullException
     }
 }
理想情况下,在尝试关联图像包之前,您应该检查艺术家是否存在。这将发生在立面之外


还可以看看工厂模式。您可以实现这一点,而不是自己创建对象。还可以看看单例模式。立面和工厂通常是单体的。

系统及其API应该

  • 显而易见
  • 可预测的
  • 和沟通
例如,Evans的“领域驱动设计”(如第10章“柔性设计”)中描述了这一点。我认为这些想法是一个很好的理由,甚至超出了DDD的范围

函数应该没有副作用,这意味着它们应该只做一件事。所以我认为你的函数“createImagePack”不应该有创建艺术家的明显副作用

您的API可以通过使用意图显示接口来预测

你的API是什么?在我看来,您应该为艺术家、图像、图像包提供单独的域模型类。。。如果有一个方便的方法在更高的层次上抽象处理,那么它应该是一个facade。但是命名应该清楚地传达它的功能

也许您甚至应该后退一步,查看应用程序的域。也许你的应用程序不应该在没有现有艺术家的情况下处理图像或图像包。也许它应该更像[艺术家]->[创建图像包]。这可能比反过来更明显

我是不是分析过度了

我不这么认为

他们关于什么是最好的行动方针的优秀评论是什么

你可以看看DDD的想法。即使您不以DDD方式设计应用程序

另一种可能性是研究测试驱动的开发。如果你