![Cache](https://quera.org/qbox/view/zX6b6YCwyp/cache.png)
طبق [آماری که گوگل در سال ۲۰۱۶ منتشر کرد](https://www.blog.google/products/admanager/increase-speed-of-your-mobile-site-wi/)، ٪۵۳ از بازدیدکنندگان، یک وبسایت را در صورتی که لود آن بیش از ۳ ثانیه طول بکشد رها میکنند! این آمار، ابوالفضل را به این فکر فرو برده که سرعت لود یک وبسایت به چه اندازه روی حس رضایت کاربران آن وبسایت تأثیر دارد. او که حالا هشتگ `#SpeedMatters` را در شبکههای اجتماعی ترند کرده، به این فکر افتاده که سرعت لود برنامهاش را با استفاده از *cache* بالا ببرد. او برای این کار نیاز به یک دولوپر دیگر دارد و از شما کمک خواسته است.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/problemset/assignments/4367/download_problem_initial_project/169496/) دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
```
cache
├── models
│ ├── CacheData.java
│ ├── Comment.java
│ ├── ExportCacheDTO.java
│ └── Photo.java
├── services
│ ├── Cache.java
│ └── CacheItem.java
└── Application.java
```
شما باید کلاس `Cache` را طوری کامل کنید تا خواستههایی را که در ادامه مطرح میشود را برآورده کند.
ساختار اولیهی این کلاس بهصورت زیر است:
```java services/Cache.java java
package services;
import java.util.ArrayList;
import java.util.List;
public class Cache {
private static final int TTL = 2;
private List<CacheItem> data = new ArrayList<>();
public List<CacheItem> getAll() {
return data;
}
}
```
همانطور که مشخص است، *cache* ما قرار است آیتمهای مختلفی را توسط کلاس `CacheItem` درون خود نگه دارد. این آیتمها فعلاً شامل دو کلاس `Photo` و `Comment` میشوند. همچنین این آیتمها زمان مجازی دارند که توسط پراپرتی `TTL` (واحد روز) مشخص میشود. در اولین گام باید کلاس `CacheItem` را کامل کنید.
## اینترفیس `CacheData`
این اینترفیس، بیانگر دادههای موجود در *cache* است. متد زیر در این اینترفیس تعریف شده است:
```java
long getID();
```
کلاسهای `Comment` و `Photo` این اینترفیس را پیادهسازی میکنند.
## کلاس `CacheItem`
این کلاس بهصورت *generic* بوده و مشخصکنندهی آیتمهایی است که درون *cache* نگه داشته میشوند. این کلاس باید شامل دو پراپرتی `data` از نوع `T` (بهصورت *generic*) و `createdAt` از نوع `LocalDateTime` باشد.
از پراپرتی `createdAt` برای بررسی مجاز بودن یک آیتم *cache* استفاده میشود. زمان مجاز زنده بودن یک آیتم درون *cache* طبق مقدار پراپرتی `TTL` در کلاس `Cache` برابر با **۲ روز** است.
## کلاس `Cache`
همانطور که گفته شد، مهمترین بخش برنامه، این کلاس است. شما باید متدهایی را که در ادامه ذکر میشود را در این کلاس پیادهسازی کنید:
+ متد `add`: این متد که ورودی آن `CacheItem` است، باید بتواند یک آیتم را به *cache* اضافه کند. **دقت کنید** که آیتمی با دیتای تکراری نباید در *cache* وجود داشته باشد. در اینصورت، آیتم قبلی باید از لیست آیتمها حذف شده و آیتم جدید درج شود.
+ متد `remove`: این متد که ورودی آن `CacheItem` است، باید بتواند یک آیتم را از *cache* حذف کند.
دو متد بالا را باید بتوان به روش *method chaining* صدا زد. مثال:
```java
cache.add(item1).remove(item1).add(item2);
```
+ متد `clear`: این متد تمام آیتمهای درون *cache* را حذف میکند.
+ متد `getAll`: این متد تمام آیتمهای مجاز درون *cache* را در قالب لیستی از `CacheItem`ها برمیگرداند.
+ متد `findByID`: این متد یک پارامتر ورودی از نوع `long` دارد و باید لیستی از `CacheItem`های مجاز را در صورتی که پراپرتی `ID` آیتم درون *cache* با پارامتر ورودی برابر بود برگرداند.
+ متد `filter`: این متد دو امضا بهصورت زیر دارد:
+ اولین امضای این متد دو پارامتر ورودی دارد. اولین پارامتر، نام پراپرتی از نوع `String` است. دومین پارامتر، یک عبارت باقاعده (*Regex*) بهصورت `String` است. در این حالت، **تضمین میشود** که پراپرتیای با نام ذکرشده در همهی دادههای موجود در *cache* تعریف شده است.
+ دومین امضای این متد نیز مانند امضای اول است، فقط پارامتر نوع کلاس بهعنوان اولین پارامتر به این متد اضافه شده و مشخصکنندهی نوع کلاسی است که باید جستوجو فقط در دادههای از نوع کلاس واردشده صورت گیرد. در این حالت، **تضمین میشود** که پراپرتیای با نام ذکرشده در کلاس ذکرشده تعریف شده است.
کاری که این متد انجام میدهد آن است که باید در پراپرتی گفتهشده، عبارت باقاعده را جستوجو کند و لیستی از `CacheItem`های مجاز را برگرداند. به عنوان مثال فرض کنید دو آیتم زیر درون *cache* وجود دارند:
```
Photo{ID=1, name='tree.png', path='/production', size=10.0}
Photo{ID=2, name='weather.jpg', path='/production', size=10.0}
```
حال متد `filter` را بهصورت زیر صدا میزنیم و میخواهیم عکسهای با فرمت `png` را فیلتر کنیم:
```java Application.java java
cache.filter(Photo.class, "name", ".png")
```
خروجی باید بهصورت زیر باشد:
```
Photo{ID=1, name='tree.png', path='/production', size=10.0}
```
+ متد `export`: از این متد نیز قرار است برای بهدست آوردن آماری در رابطه با آیتمهای درون *cache* استفاده کنیم. خروجی این متد لیستی از `ExportCacheDTO`ها است. مثالی از خروجی این متد:
```
[
ExportCacheDTO{name='Photo', size=2},
ExportCacheDTO{name='Comment', size=3}
]
```
این خروجی به این معنی است که ۲ آیتم از نوع `Photo` و ۳ آیتم از نوع `Comment` درون *cache* وجود دارد.
# نکات
+ آیتمی با دیتای تکراری نباید در *cache* وجود داشته باشد.
+ اگر قرار است در بعضی از متدها آیتمی را برگردانید، آن آیتم حتماً باید مجاز باشد (منقضی نشده باشد).
+ ترتیب برگرداندن آیتمها باید مطابق با ترتیب اضافه شدن آنها به *cache* باشد.
+ شما تنها مجاز به اعمال تغییرات در فایلهای `services/Cache.java` و `services/CacheItem.java` هستید.
+ تستهای نمونهی برنامه در کلاس `CacheSampleTest` موجود هستند. میتوانید آنها را پس از افزودن *JUnit* به *classpath* در سیستم خود اجرا کنید.
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواستهشده، پوشهی `services` را زیپ کرده و آپلود کنید (خود پوشه نیز در فایل زیپ موجود باشد).