Fluent APIãšåå®å šæ§ã«çŠç¹ãåœãŠããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã®è©³çްãªè§£èª¬ãçŸä»£ã®ããã°ã©ãã³ã°ãã©ãã€ã ã«ãããäŸä»ãã
ãžã§ããªãã¯ãã«ããŒãã¿ãŒã³ïŒFluent APIåå®è£ ã®è§£æŸ
ãã«ããŒãã¿ãŒã³ã¯ãè€éãªãªããžã§ã¯ãã®æ§ç¯ããã®è¡šçŸããåé¢ããçæãã¶ã€ã³ãã¿ãŒã³ã§ããããã«ãããåãæ§ç¯ããã»ã¹ã§ç°ãªã衚çŸãäœæã§ããŸãããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã¯ãåå®å šæ§ãšåå©çšæ§ãå°å ¥ããããšã«ããããã®æŠå¿µãæ¡åŒµãããã衚çŸåè±ãã§èªã¿ãããæ§ç¯ããã»ã¹ã®ããã«ãå€ãã®å ŽåFluent APIãšçµã¿åããããŸãããã®èšäºã§ã¯ãFluent APIåå®è£ ã«çŠç¹ãåœãŠãŠããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ãæ€èšããæŽå¯ãšå®è·µçãªäŸãæäŸããŸãã
åŸæ¥ã®ãã«ããŒãã¿ãŒã³ã®çè§£
ãžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã«å ¥ãåã«ãåŸæ¥ã®ãã«ããŒãã¿ãŒã³ã埩ç¿ããŸãããã`Computer`ãªããžã§ã¯ããæ§ç¯ããŠãããšæ³åããŠãã ãããã°ã©ãã£ãã¯ã«ãŒãã远å ã®RAMããµãŠã³ãã«ãŒããªã©ãå€ãã®ãªãã·ã§ã³ã³ã³ããŒãã³ããæã€ããšãã§ããŸããå€ãã®ãªãã·ã§ã³ãã©ã¡ãŒã¿ïŒãã¬ã¹ã³ãŒãã³ã°ã³ã³ã¹ãã©ã¯ã¿ïŒãæã€ã³ã³ã¹ãã©ã¯ã¿ã䜿çšãããšãæ±ãã«ãããªããŸãããã«ããŒãã¿ãŒã³ã¯ãå¥ã®ãã«ããŒã¯ã©ã¹ãæäŸããããšã«ãããããã解決ããŸãã
äŸïŒæŠå¿µçïŒïŒ
代ããã«ïŒ
Computer computer = new Computer(ram, hdd, cpu, graphicsCard, soundCard);
以äžã䜿çšããŸãïŒ
Computer computer = new ComputerBuilder()
.setRam(ram)
.setHdd(hdd)
.setCpu(cpu)
.setGraphicsCard(graphicsCard)
.build();
ãã®ã¢ãããŒãã«ã¯ãããã€ãã®å©ç¹ããããŸãã
- å¯èªæ§ïŒã³ãŒãã¯ããèªã¿ããããèªå·±ææžåãããŠããŸãã
- æè»æ§ïŒæ¢åã®ã³ãŒãã«åœ±é¿ãäžããããšãªãããªãã·ã§ã³ã®ãã©ã¡ãŒã¿ãç°¡åã«è¿œå ãŸãã¯åé€ã§ããŸãã
- ã€ãã¥ãŒã¿ããªãã£ïŒæçµçãªãªããžã§ã¯ãã¯ã€ãã¥ãŒã¿ãã«ã«ããããšãã§ããã¹ã¬ããã®å®å šæ§ãšäºæž¬å¯èœæ§ãé«ããŸãã
ãžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã®ç޹ä»
ãžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã¯ããžã§ããªãã¯ãå°å ¥ããããšã«ãããåŸæ¥ã®ãã«ããŒãã¿ãŒã³ãããã«äžæ©é²ããŸããããã«ãããããŸããŸãªãªããžã§ã¯ãã¿ã€ãã§ã¿ã€ãã»ãŒãã§åå©çšå¯èœãªãã«ããŒãäœæã§ããŸããéèŠãªåŽé¢ã¯ãå€ãã®å ŽåãFluent APIã®å®è£ ã§ãããããæµåçã§è¡šçŸåè±ããªæ§ç¯ããã»ã¹ã®ããã«ã¡ãœãããã§ãŒã³ãå¯èœã«ããŸãã
ãžã§ããªãã¯ãšFluent APIã®å©ç¹
- åå®å šæ§ïŒã³ã³ãã€ã©ã¯ãæ§ç¯ããã»ã¹äžã«äžæ£ãªåã«é¢é£ãããšã©ãŒããã£ããããã©ã³ã¿ã€ã ã®åé¡ã軜æžã§ããŸãã
- åå©çšæ§ïŒåäžã®ãžã§ããªãã¯ãã«ããŒå®è£ ã䜿çšããŠãããŸããŸãªã¿ã€ãã®ãªããžã§ã¯ããæ§ç¯ã§ãããããã³ãŒãã®éè€ãåæžãããŸãã
- 衚çŸåïŒFluent APIã«ãããã³ãŒããããèªã¿ããããçè§£ãããããªããŸããã¡ãœãããã§ãŒã³ã¯ããªããžã§ã¯ãæ§ç¯çšã®ãã¡ã€ã³åºæèšèªïŒDSLïŒãäœæããŸãã
- ä¿å®æ§ïŒã³ãŒãã¯ããã®ã¢ãžã¥ãŒã«åŒã§åå®å šãªæ§è³ªã«ãããä¿å®ããã³é²åã容æã§ãã
Fluent APIã䜿çšãããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã®å®è£
ããã€ãã®èšèªã§Fluent APIã䜿çšãããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ãå®è£ ããæ¹æ³ãèŠãŠã¿ãŸããããã³ã¢ã³ã³ã»ããã«çŠç¹ãåœãŠãå ·äœçãªäŸã§ã¢ãããŒãã瀺ããŸãã
äŸ1ïŒJava
Javaã§ã¯ããžã§ããªãã¯ãšã¡ãœãããã§ãŒã³ã掻çšããŠãã¿ã€ãã»ãŒãã§Fluentãªãã«ããŒãäœæã§ããŸãã`Person`ã¯ã©ã¹ãèããŠã¿ãŸãããã
public class Person {
private final String firstName;
private final String lastName;
private final int age;
private final String address;
private Person(String firstName, String lastName, int age, String address) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.address = address;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public String getAddress() {
return address;
}
public static class Builder {
private String firstName;
private String lastName;
private int age;
private String address;
public Builder firstName(String firstName) {
this.firstName = firstName;
return this;
}
public Builder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Person build() {
return new Person(firstName, lastName, age, address);
}
}
}
//Usage:
Person person = new Person.Builder()
.firstName("John")
.lastName("Doe")
.age(30)
.address("123 Main St")
.build();
ããã¯åºæ¬çãªäŸã§ãããFluent APIãšã€ãã¥ãŒã¿ããªãã£ã匷調ããŠããŸããçã«*ãžã§ããªãã¯*ãªãã«ããŒã®å Žåãããå€ãã®æœè±¡åãå°å ¥ããæœåšçã«ãªãã¬ã¯ã·ã§ã³ãŸãã¯ã³ãŒãçæææ³ã䜿çšããŠãããŸããŸãªåãåçã«åŠçããå¿ èŠããããŸããGoogleã®AutoValueãªã©ã®ã©ã€ãã©ãªã䜿çšãããšãJavaã§ã€ãã¥ãŒã¿ãã«ãªããžã§ã¯ãã®ãã«ããŒã®äœæãå€§å¹ ã«ç°¡çŽ åã§ããŸãã
äŸ2ïŒC#
C#ã¯ããžã§ããªãã¯ã§Fluentãªãã«ããŒãäœæããããã®åæ§ã®æ©èœãæäŸããŸãã`Product`ã¯ã©ã¹ã䜿çšããäŸã次ã«ç€ºããŸãã
public class Product
{
public string Name { get; private set; }
public decimal Price { get; private set; }
public string Description { get; private set; }
private Product(string name, decimal price, string description)
{
Name = name;
Price = price;
Description = description;
}
public class Builder
{
private string _name;
private decimal _price;
private string _description;
public Builder WithName(string name)
{
_name = name;
return this;
}
public Builder WithPrice(decimal price)
{
_price = price;
return this;
}
public Builder WithDescription(string description)
{
_description = description;
return this;
}
public Product Build()
{
return new Product(_name, _price, _description);
}
}
}
//Usage:
Product product = new Product.Builder()
.WithName("Laptop")
.WithPrice(1200.00m)
.WithDescription("High-performance laptop")
.Build();
C#ã§ã¯ãæ¡åŒµã¡ãœããã䜿çšããŠFluent APIãããã«åŒ·åããããšãã§ããŸããããšãã°ãå€éšããŒã¿ãŸãã¯æ¡ä»¶ã«åºã¥ããŠãã«ããŒã«ç¹å®ã®æ§æãªãã·ã§ã³ã远å ããæ¡åŒµã¡ãœãããäœæã§ããŸãã
äŸ3ïŒTypeScript
JavaScriptã®ã¹ãŒããŒã»ããã§ããTypeScriptã§ãããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã®å®è£ ãå¯èœã§ããããã§ã¯ãåå®å šæ§ãäž»ãªå©ç¹ã§ãã
class Configuration {
public readonly host: string;
public readonly port: number;
public readonly timeout: number;
private constructor(host: string, port: number, timeout: number) {
this.host = host;
this.port = port;
this.timeout = timeout;
}
static get Builder(): ConfigurationBuilder {
return new ConfigurationBuilder();
}
}
class ConfigurationBuilder {
private host: string = "localhost";
private port: number = 8080;
private timeout: number = 3000;
withHost(host: string): ConfigurationBuilder {
this.host = host;
return this;
}
withPort(port: number): ConfigurationBuilder {
this.port = port;
return this;
}
withTimeout(timeout: number): ConfigurationBuilder {
this.timeout = timeout;
return this;
}
build(): Configuration {
return new Configuration(this.host, this.port, this.timeout);
}
}
//Usage:
const config = Configuration.Builder
.withHost("example.com")
.withPort(80)
.build();
console.log(config.host); // Output: example.com
console.log(config.port); // Output: 80
TypeScriptã®åã·ã¹ãã ã¯ããã«ããŒã¡ãœãããæ£ããåãåãåããæçµçãªãªããžã§ã¯ããäºæãããããããã£ã§æ§ç¯ãããããšãä¿èšŒããŸããã€ã³ã¿ãŒãã§ã€ã¹ãšæœè±¡ã¯ã©ã¹ã掻çšããŠãããæè»ã§åå©çšå¯èœãªãã«ããŒå®è£ ãäœæã§ããŸãã
é«åºŠãªèæ ®äºé ïŒçã«ãžã§ããªãã¯ã«ãã
äžèšã®äŸã¯ãFluent APIã䜿çšãããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã®åºæ¬ååã瀺ããŠããŸãããã ããããŸããŸãªãªããžã§ã¯ãã¿ã€ããåŠçã§ããçã«*ãžã§ããªãã¯*ãªãã«ããŒãäœæããã«ã¯ãããé«åºŠãªææ³ãå¿ èŠã§ããããã€ãã®èæ ®äºé ãæ¬¡ã«ç€ºããŸãã
- ãªãã¬ã¯ã·ã§ã³ïŒãªãã¬ã¯ã·ã§ã³ã䜿çšãããšãã¿ãŒã²ãããªããžã§ã¯ãã®ããããã£ãæ€æ»ãããããã®å€ãåçã«èšå®ã§ããŸãããã®ã¢ãããŒãã¯è€éã«ãªãå¯èœæ§ããããããã©ãŒãã³ã¹ã«åœ±é¿ãäžããå¯èœæ§ããããŸãã
- ã³ãŒãçæïŒã¢ãããŒã·ã§ã³ããã»ããµïŒJavaïŒãŸãã¯ãœãŒã¹ãžã§ãã¬ãŒã¿ïŒC#ïŒã®ãããªããŒã«ã¯ãã¿ãŒã²ãããªããžã§ã¯ãã®å®çŸ©ã«åºã¥ããŠãã«ããŒã¯ã©ã¹ãèªåçã«çæã§ããŸãããã®ã¢ãããŒãã¯åå®å šæ§ãæäŸããã©ã³ã¿ã€ã ãªãã¬ã¯ã·ã§ã³ãåé¿ããŸãã
- æœè±¡ãã«ããŒã€ã³ã¿ãŒãã§ã€ã¹ïŒãªããžã§ã¯ãã®æ§ç¯ã®ããã®å ±éAPIãæäŸããæœè±¡ãã«ããŒã€ã³ã¿ãŒãã§ã€ã¹ãŸãã¯åºæ¬ã¯ã©ã¹ãå®çŸ©ããŸããããã«ãããäžè²«ããã€ã³ã¿ãŒãã§ã€ã¹ãç¶æããªãããããŸããŸãªãªããžã§ã¯ãã¿ã€ãã«å¯ŸããŠç¹æ®ãªãã«ããŒãäœæã§ããŸãã
- ã¡ã¿ããã°ã©ãã³ã°ïŒè©²åœããå ŽåïŒïŒåŒ·åãªã¡ã¿ããã°ã©ãã³ã°æ©èœãåããèšèªã¯ãã³ã³ãã€ã«æã«ãã«ããŒãåçã«äœæã§ããŸãã
ã€ãã¥ãŒã¿ããªãã£ã®åŠç
ã€ãã¥ãŒã¿ããªãã£ã¯ããã«ããŒãã¿ãŒã³ã䜿çšããŠäœæããããªããžã§ã¯ãã®æãŸããç¹æ§ã§ããããšããããããŸããã€ãã¥ãŒã¿ãã«ãªããžã§ã¯ãã¯ã¹ã¬ããã»ãŒãã§ãããæšè«ã容æã§ããã€ãã¥ãŒã¿ããªãã£ã確ä¿ããã«ã¯ã次ã®ã¬ã€ãã©ã€ã³ã«åŸã£ãŠãã ããã
- ã¿ãŒã²ãããªããžã§ã¯ãã®ãã¹ãŠã®ãã£ãŒã«ãã`final`ïŒJavaïŒã«ãããã`get`ã¢ã¯ã»ãµã®ã¿ãæã€ããããã£ïŒC#ïŒã䜿çšããŸãã
- ã¿ãŒã²ãããªããžã§ã¯ãã®ãã£ãŒã«ãã«ã»ãã¿ãŒã¡ãœãããæäŸããªãã§ãã ããã
- ã¿ãŒã²ãããªããžã§ã¯ãã«å¯å€ã³ã¬ã¯ã·ã§ã³ãŸãã¯é åãå«ãŸããŠããå Žåã¯ãã³ã³ã¹ãã©ã¯ã¿ã§é²åŸ¡çã³ããŒãäœæããŸãã
è€éãªæ€èšŒã®åŠç
ãã«ããŒãã¿ãŒã³ã䜿çšããŠããªããžã§ã¯ãæ§ç¯äžã«è€éãªæ€èšŒã«ãŒã«ãé©çšããããšãã§ããŸãããã«ããŒã®`build()`ã¡ãœãããŸãã¯åã ã®ã»ãã¿ãŒã¡ãœããå ã«æ€èšŒããžãã¯ã远å ã§ããŸããæ€èšŒã倱æããå Žåã¯ãäŸå€ãã¹ããŒãããããšã©ãŒãªããžã§ã¯ããè¿ããŸãã
å®éã®ã¢ããªã±ãŒã·ã§ã³
Fluent APIã䜿çšãããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã¯ã次ã®ãããªããŸããŸãªã·ããªãªã«é©çšã§ããŸãã
- æ§æç®¡çïŒå€æ°ã®ãªãã·ã§ã³ãã©ã¡ãŒã¿ãå«ãè€éãªæ§æãªããžã§ã¯ãã®æ§ç¯ã
- ããŒã¿è»¢éãªããžã§ã¯ãïŒDTOïŒïŒã¢ããªã±ãŒã·ã§ã³ã®ç°ãªãã¬ã€ã€ãŒéã§ããŒã¿ã転éããããã®DTOã®äœæã
- APIã¯ã©ã€ã¢ã³ãïŒããŸããŸãªããããŒããã©ã¡ãŒã¿ãããã³ãã€ããŒãã䜿çšããŠAPIãªã¯ãšã¹ããªããžã§ã¯ããæ§ç¯ã
- ãã¡ã€ã³é§åèšèšïŒDDDïŒïŒè€éãªé¢ä¿ãšæ€èšŒã«ãŒã«ãæã€è€éãªãã¡ã€ã³ãªããžã§ã¯ãã®æ§ç¯ã
äŸïŒAPIãªã¯ãšã¹ãã®æ§ç¯
仮説çãªeã³ããŒã¹ãã©ãããã©ãŒã çšã®APIãªã¯ãšã¹ããªããžã§ã¯ãã®æ§ç¯ãæ€èšããŠãã ããããªã¯ãšã¹ãã«ã¯ãAPIãšã³ããã€ã³ããHTTPã¡ãœãããããããŒããªã¯ãšã¹ãããã£ãªã©ã®ãã©ã¡ãŒã¿ãå«ãŸããå ŽåããããŸãã
ãžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã䜿çšãããšããããã®ãªã¯ãšã¹ããæ§ç¯ããããã®æè»ã§ã¿ã€ãã»ãŒããªæ¹æ³ãäœæã§ããŸãã
//Conceptual Example
ApiRequest request = new ApiRequestBuilder()
.withEndpoint("/products")
.withMethod("GET")
.withHeader("Authorization", "Bearer token")
.withParameter("category", "electronics")
.build();
ãã®ã¢ãããŒãã«ãããåºã«ãªãã³ãŒãã倿Žããã«ããªã¯ãšã¹ããã©ã¡ãŒã¿ãç°¡åã«è¿œå ãŸãã¯å€æŽã§ããŸãã
ãžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã®ä»£æ¿
ãžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã¯å€§ããªå©ç¹ãæäŸããŸããã代æ¿ã¢ãããŒããæ€èšããããšãéèŠã§ãã
- ãã¬ã¹ã³ãŒãã³ã°ã³ã³ã¹ãã©ã¯ã¿ïŒåè¿°ã®ããã«ããã¬ã¹ã³ãŒãã³ã°ã³ã³ã¹ãã©ã¯ã¿ã¯ãå€ãã®ãªãã·ã§ã³ãã©ã¡ãŒã¿ã䜿çšãããšæ±ãã«ãããªãå¯èœæ§ããããŸãã
- ãã¡ã¯ããªãã¿ãŒã³ïŒãã¡ã¯ããªãã¿ãŒã³ã¯ãªããžã§ã¯ãã®äœæã«çŠç¹ãåœãŠãŠããŸãããå€ãã®ãªãã·ã§ã³ãã©ã¡ãŒã¿ã䜿çšãããªããžã§ã¯ãæ§ç¯ã®è€éãã«ã¯å¿ ããã察åŠããŠããŸããã
- LombokïŒJavaïŒïŒLombokã¯ããã«ããŒãå«ããã€ã©ãŒãã¬ãŒãã³ãŒããèªåçã«çæããJavaã©ã€ãã©ãªã§ããèšè¿°ããå¿ èŠã®ããã³ãŒãéãå€§å¹ ã«åæžã§ããŸãããLombokãžã®äŸåé¢ä¿ãå°å ¥ãããŸãã
- ã¬ã³ãŒãåïŒJava 14+ / C# 9+ïŒïŒã¬ã³ãŒãã¯ãã€ãã¥ãŒã¿ãã«ããŒã¿ã¯ã©ã¹ãå®çŸ©ããããã®ç°¡æœãªæ¹æ³ãæäŸããŸãããã«ããŒãã¿ãŒã³ãçŽæ¥ãµããŒãããŠããŸããããã¬ã³ãŒãã®ãã«ããŒã¯ã©ã¹ãç°¡åã«äœæã§ããŸãã
çµè«
Fluent APIãšçµã¿åããããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã¯ãã¿ã€ãã»ãŒãã§èªã¿ããããä¿å®å¯èœãªæ¹æ³ã§è€éãªãªããžã§ã¯ããäœæããããã®åŒ·åãªããŒã«ã§ãããã®èšäºã§èª¬æããåºæ¬ååãçè§£ããé«åºŠãªææ³ãæ€èšããããšã§ããããžã§ã¯ãã§ãã®ãã¿ãŒã³ã广çã«æŽ»çšããŠãã³ãŒãå質ãåäžãããéçºæéãççž®ã§ããŸããããŸããŸãªããã°ã©ãã³ã°èšèªã§æäŸãããŠããäŸã¯ããã¿ãŒã³ã®æ±çšæ§ãšãããŸããŸãªå®éã®ã·ããªãªã§ã®é©çšæ§ã瀺ããŠããŸããã³ãŒãã®è€éããããã©ãŒãã³ã¹èŠä»¶ãèšèªæ©èœãªã©ã®èŠçŽ ãèæ ®ããŠãç¹å®ã®ããŒãºãšããã°ã©ãã³ã°ã³ã³ããã¹ãã«æé©ãªã¢ãããŒããéžæããããšãå¿ããªãã§ãã ããã
æ§æãªããžã§ã¯ããDTOããŸãã¯APIã¯ã©ã€ã¢ã³ããæ§ç¯ããå Žåã§ãããžã§ããªãã¯ãã«ããŒãã¿ãŒã³ã¯ãããå ç¢ã§ãšã¬ã¬ã³ããªãœãªã¥ãŒã·ã§ã³ãäœæããã®ã«åœ¹ç«ã¡ãŸãã
ãããªãæ¢æ±
- ãã«ããŒãã¿ãŒã³ã®åºç€çãªçè§£ã«ã€ããŠã¯ãErich GammaãRichard HelmãRalph Johnsonãããã³John VlissidesïŒGang of FourïŒã«ãããDesign Patterns: Elements of Reusable Object-Oriented Softwareãããèªã¿ãã ããã
- ãã«ããŒã®äœæãç°¡çŽ åããããã«ãAutoValueïŒJavaïŒãLombokïŒJavaïŒãªã©ã®ã©ã€ãã©ãªãæ€èšããŠãã ããã
- ãã«ããŒã¯ã©ã¹ãèªåçã«çæããããã«ãC#ã®ãœãŒã¹ãžã§ãã¬ãŒã¿ã調ã¹ãŠãã ããã