|
| 1 | +package com.iluwatar.caching; |
| 2 | + |
| 3 | +/** |
| 4 | + * |
| 5 | + * The Caching pattern describes how to avoid expensive re-acquisition of resources by not releasing |
| 6 | + * the resources immediately after their use. The resources retain their identity, are kept in some |
| 7 | + * fast-access storage, and are re-used to avoid having to acquire them again. There are three main |
| 8 | + * caching strategies/techniques in this pattern; each with their own pros and cons. They are: |
| 9 | + * <code>write-through</code> which writes data to the cache and DB in a single transaction, |
| 10 | + * <code>write-around</code> which writes data immediately into the DB instead of the cache, and |
| 11 | + * <code>write-behind</code> which writes data into the cache initially whilst the data is only |
| 12 | + * written into the DB when the cache is full. The <code>read-through</code> strategy is also |
| 13 | + * included in the mentioned three strategies -- returns data from the cache to the caller <b>if</b> |
| 14 | + * it exists <b>else</b> queries from DB and stores it into the cache for future use. These |
| 15 | + * strategies determine when the data in the cache should be written back to the backing store (i.e. |
| 16 | + * Database) and help keep both data sources synchronized/up-to-date. This pattern can improve |
| 17 | + * performance and also helps to maintain consistency between data held in the cache and the data in |
| 18 | + * the underlying data store. |
| 19 | + * <p> |
| 20 | + * In this example, the user account ({@link UserAccount}) entity is used as the underlying |
| 21 | + * application data. The cache itself is implemented as an internal (Java) data structure. It adopts |
| 22 | + * a Least-Recently-Used (LRU) strategy for evicting data from itself when its full. The three |
| 23 | + * strategies are individually tested. The testing of the cache is restricted towards saving and |
| 24 | + * querying of user accounts from the underlying data store ( {@link DBManager}). The main class ( |
| 25 | + * {@link App} is not aware of the underlying mechanics of the application (i.e. save and query) and |
| 26 | + * whether the data is coming from the cache or the DB (i.e. separation of concern). The AppManager |
| 27 | + * ({@link AppManager}) handles the transaction of data to-and-from the underlying data store |
| 28 | + * (depending on the preferred caching policy/strategy). |
| 29 | + * |
| 30 | + * <i>App --> AppManager --> CacheStore/LRUCache/CachingPolicy --> DBManager</i> |
| 31 | + * </p> |
| 32 | + * |
| 33 | + * @see CacheStore |
| 34 | + * @See LRUCache |
| 35 | + * @see CachingPolicy |
| 36 | + * |
| 37 | + */ |
| 38 | +public class App { |
| 39 | + |
| 40 | + /** |
| 41 | + * Program entry point |
| 42 | + * |
| 43 | + * @param args command line args |
| 44 | + */ |
| 45 | + public static void main(String[] args) { |
| 46 | + AppManager.initDB(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests |
| 47 | + // and the App class to avoid Maven compilation errors. Set flag to |
| 48 | + // true to run the tests with MongoDB (provided that MongoDB is |
| 49 | + // installed and socket connection is open). |
| 50 | + AppManager.initCacheCapacity(3); |
| 51 | + App app = new App(); |
| 52 | + app.useReadAndWriteThroughStrategy(); |
| 53 | + app.useReadThroughAndWriteAroundStrategy(); |
| 54 | + app.useReadThroughAndWriteBehindStrategy(); |
| 55 | + } |
| 56 | + |
| 57 | + /** |
| 58 | + * Read-through and write-through |
| 59 | + */ |
| 60 | + public void useReadAndWriteThroughStrategy() { |
| 61 | + System.out.println("# CachingPolicy.THROUGH"); |
| 62 | + AppManager.initCachingPolicy(CachingPolicy.THROUGH); |
| 63 | + |
| 64 | + UserAccount userAccount1 = new UserAccount("001", "John", "He is a boy."); |
| 65 | + |
| 66 | + AppManager.save(userAccount1); |
| 67 | + System.out.println(AppManager.printCacheContent()); |
| 68 | + userAccount1 = AppManager.find("001"); |
| 69 | + userAccount1 = AppManager.find("001"); |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * Read-through and write-around |
| 74 | + */ |
| 75 | + public void useReadThroughAndWriteAroundStrategy() { |
| 76 | + System.out.println("# CachingPolicy.AROUND"); |
| 77 | + AppManager.initCachingPolicy(CachingPolicy.AROUND); |
| 78 | + |
| 79 | + UserAccount userAccount2 = new UserAccount("002", "Jane", "She is a girl."); |
| 80 | + |
| 81 | + AppManager.save(userAccount2); |
| 82 | + System.out.println(AppManager.printCacheContent()); |
| 83 | + userAccount2 = AppManager.find("002"); |
| 84 | + System.out.println(AppManager.printCacheContent()); |
| 85 | + userAccount2 = AppManager.find("002"); |
| 86 | + userAccount2.setUserName("Jane G."); |
| 87 | + AppManager.save(userAccount2); |
| 88 | + System.out.println(AppManager.printCacheContent()); |
| 89 | + userAccount2 = AppManager.find("002"); |
| 90 | + System.out.println(AppManager.printCacheContent()); |
| 91 | + userAccount2 = AppManager.find("002"); |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Read-through and write-behind |
| 96 | + */ |
| 97 | + public void useReadThroughAndWriteBehindStrategy() { |
| 98 | + System.out.println("# CachingPolicy.BEHIND"); |
| 99 | + AppManager.initCachingPolicy(CachingPolicy.BEHIND); |
| 100 | + |
| 101 | + UserAccount userAccount3 = new UserAccount("003", "Adam", "He likes food."); |
| 102 | + UserAccount userAccount4 = new UserAccount("004", "Rita", "She hates cats."); |
| 103 | + UserAccount userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard."); |
| 104 | + |
| 105 | + AppManager.save(userAccount3); |
| 106 | + AppManager.save(userAccount4); |
| 107 | + AppManager.save(userAccount5); |
| 108 | + System.out.println(AppManager.printCacheContent()); |
| 109 | + userAccount3 = AppManager.find("003"); |
| 110 | + System.out.println(AppManager.printCacheContent()); |
| 111 | + UserAccount userAccount6 = new UserAccount("006", "Yasha", "She is an only child."); |
| 112 | + AppManager.save(userAccount6); |
| 113 | + System.out.println(AppManager.printCacheContent()); |
| 114 | + userAccount4 = AppManager.find("004"); |
| 115 | + System.out.println(AppManager.printCacheContent()); |
| 116 | + } |
| 117 | +} |
0 commit comments