معرفی DTO, Java Bean و POJO در جاوا

سلام :)

خب اجازه بدید از DTO شروع کنیم، DTO یا Data Transfer Object در جاوا یک شی جهت انتقال داده ها بین زیرسیستم ها یا بخش های متفاوت پروژه و یک الگوی طراحی سازمانی(aggregate) برای جمع آوری داده ها است.

DTO, Java Bean, POJO
DTO, Java Bean, POJO

قبل اینکه بیشتر ادامه بدیم چنتا مفهوم رو باید روشن کنیم، POJO و Java Bean

یک Plain Old Java Object (POJO) یک شیء معمولی جاوا است. که می تواند هر کلاسی باشد و هیچ محدودیت خاصی غیر از مواردی که توسط زبان جاوا تجویز شده است، محدود نمی شود و برای قابلیت استفاده مجدد و افزایش خوانایی ایجاد شده اند.

public class CoffeePOJO {
   public String name;
   private List<String> ingredients;
   public CoffeePOJO(String name, List<String> ingredients) { 
            this.name = name;
       this.ingredients = ingredients;
   }

   void addIngredient(String ingredient) {
       ingredients.add(ingredient);
   }
}

همانطور که در مثال بالا مشاهده میکنید ما یک کلاس معمولی جاوا داریم :) اما یکسری نکات وجود داره که کلاس بالا یک POJO هست اما یک Java Bean نیست چرا که Java Beanها از یک سری استانداردها تحت عنوان JavaBean standard پیروی میکنند و هرکلاس POJO که این استاندارد ها را داشته باشد یک Java Bean هستش.

بر اساس این استاندارد، تمام ویژگی ها(properties) خصوصی هستند(private) و با متدهای getter و setter قابل دسترسی خواهند بود. علاوه بر این، یک سازنده بدون آرگ وجود داشته باشد. به همراه چند مورد دیگر.

بنابر این یک Java Bean حتما یک POJO هستش، اما هر POJO نمیتواند Java Bean باشد :)

public class CoffeeBEAN implements Serializable {
   private String name;
   private List<String> ingredients;
   public CoffeeBEAN() {
   }
   public String getName() {
       return name;
   }
   public void setName(String name) {
       this.name = name;
   }
   public List<String> getIngredients() {
       return ingredients;
   }
   public void setIngredients(List<String> ingredients) {
       this.ingredients = ingredients;
   }
}

پیاده سازی یک DTO: یک DTO را می توان به عنوان یک POJO یا یک جاوا Bean پیاده سازی کرد. مهمترین وظیفه DTO رفع نگرانی بین لایه presentation و domain model هستش

بیایید یک سرویس rest کوچک برای توضیح این موضوع بنویسیم. مثال ما یک کافی شاپ با موجودیت های قهوه و مشتری داریم. هر دوی این ها موجودیت های جداگانه ای در سیستم هستند. اگر بخواهم قهوه مورد علاقه مشتری را بدانم، یک API ایجاد می کنم که داده های محاسبه شده را در FavoriteCoffeDTO را ارائه می دهد.

کد مربوطه:

@Entity
@Getter
@Setter
public class Coffee {
   private Long id;
   private String name;
   private List<String> ingredients;
   private String preparation;
}
@Entity 
@Getter 
@Setter
public class Customer {
   private Long id;
   private String firstName;
   private String lastName;
   private List<Coffee> coffees;
}
@Getter  
@Setter
public class FavoriteCoffeeDTO {
   private String name;
   private List<String> coffees;
}

من لایه دامنه را از لایه ارائه در پیاده سازی بالا جدا کردم.

در این مثال، من فیلدها را خصوصی کردم، به این معنی که برای دسترسی به فیلدها باید متدهای getter و setter ایجاد کنم. که ما از انوتیشن @Gettrو @Setter استفاده کردیم.کاربران اغلب انتخاب می کنند که استاندارد JavaBean را به طور کامل یا جزئی برای DTO دنبال کنند. البته این اجباری نیست، شما مختارید هر روشی را انتخاب کنید که با نیازهایتان مطابقت دارد. گزینه‌های دیگر عبارتند از عمومی کردن همه فیلدها و دسترسی مستقیم به آنها (مانند مثال زیر)، یا غیرقابل تغییر کردن شی با سازنده همه آرگ‌ها و برخی روش‌های دریافت‌کننده.

public class FavoriteCoffeeDTO {
   public String name;
   public List<String> coffees;
}

String name = favCoffeeDTO.name;

در ورژن های جدید جاوا می توانیم از record ها برای ایجاد DTOها استفاده کنیم که در یک مقاله به اون پرداختیم

https://cherikcoders.ir/record-%d8%af%d8%b1-%d8%ac%d8%a7%d9%88%d8%a7/

مثال DTO با استفاده از Record:

public record FavoriteCoffeeDTO(String name, List<String> coffees) {}

String name = favoriteCoffeeDTO.name();

منبع: چریک کدرز