Singleton Design Pattern | Spring Framework | Java Beans | සිංගල්ටන් පැටර්න් | SC Guide

කොහොමද යාලුවනේ! 👋 ඔයාලා හැමෝම හොඳින් ඇති කියලා හිතනවා. අද අපි කතා කරන්න යන්නේ Software Engineering වල තියෙන ගොඩක් වැදගත් Concepts අතරින් එකක් ගැන. ඒ තමයි Design Patterns. Design Patterns කියන්නේ software development වලදී නිතරම එන Problem වලට දීලා තියෙන Standard, Proven Solutions. මේවා හරියට software architects ලා, developers ලා කාලයක් තිස්සේ හොයාගත්ත "best practices" වගේ.
අද අපි විශේෂයෙන්ම බලන්න යන්නේ Design Patterns අතරින් Creational Design Patterns ගණයට අයිති වෙන Singleton Pattern එක ගැන. මේක ගොඩක් පොදු, ඒ වගේම වැදගත් Pattern එකක්. විශේෂයෙන්ම Spring Framework එකත් එක්ක වැඩ කරනකොට Singleton Pattern එක නැතුවම බෑ. මොකද Spring එකේ default bean scope එක Singleton වීම නිසා.
හරි, එහෙනම් අපි බලමු මේ Singleton කියන්නේ මොකක්ද කියලා?
Singleton Pattern එක කියන්නේ මොකක්ද? 🤔
සරලවම කිව්වොත්, Singleton Pattern එක කියන්නේ program එකක class එකකින් හැදෙන්නේ එකම object එකක් විතරයි කියලා සහ ඒ object එකට program එකේ ඕනෑම තැනක ඉඳලා access කරන්න පුළුවන් විදියට set කරන එකටයි. හරිද?
මේක තේරුම් ගන්න ලේසිම උදාහරණයක් තමයි අපේ රටේ ජනාධිපතිතුමා. රටකට ඉන්නේ එක ජනාධිපති කෙනයි නේ? එහෙම නැත්තම් මහ බැංකුව (Central Bank) වගේ ආයතනයක්. මේ වගේ Concepts තමයි Singleton Pattern එකෙන් software එකක් ඇතුලේ Implement කරන්නේ. ඒ කියන්නේ, යම්කිසි Resource එකක් හෝ Service එකක් Global Level එකේදී එකම Instance එකකින් manage කරන්න ඕන වුණාම අපි Singleton Pattern එක පාවිච්චි කරනවා.
Singleton පාවිච්චි කරන්නේ ඇයි? (Benefits) 🚀
Singleton Pattern එක පාවිච්චි කරන්න ප්රධාන හේතු කීපයක් තියෙනවා:
- Resource Optimization: Database connections, file managers, logging utilities, configuration objects වගේ දේවල් වලදී එකම instance එකක් පාවිච්චි කරන එකෙන් system resources optimize කරගන්න පුළුවන්. හැම වෙලාවෙම අලුතින් object හදන එක නවතිනවා.
- Performance Improvement: Object creation cost එක අඩු වෙනවා. ඒ වගේම object එකක් create කරන්න යන කාලයත් ඉතුරු වෙනවා. මේක Application එකේ Overall Performance එකට හොඳයි.
- Global Access Point: සමහර වෙලාවට අපිට Application එකේ ඕනෑම තැනක ඉඳලා access කරන්න පුළුවන් Global Configuration object එකක්, Cache manager එකක් වගේ දෙයක් ඕන වෙනවා. Singleton එකකින් ඒ පහසුකම ලබා දෙනවා.
Basic Java වලින් Singleton Implement කරමු 💻
හරි, දැන් අපි බලමු Java වලින් කොහොමද සරල Singleton Class එකක් Implement කරන්නේ කියලා. මේකට ප්රධාන දේවල් තුනක් ඕන වෙනවා:
- Private Constructor: Class එකේ constructor එක private කරන්න ඕන. එතකොට අපිට කෙලින්ම
new MySingleton()
කියලා object හදන්න බැරි වෙනවා. - Static Instance: Class එක ඇතුලෙම ඒ class එකේ static instance එකක් තියාගන්න ඕන.
- Public Static Method: ඒ static instance එක return කරන public static method එකක් හදන්න ඕන. මේක තමයි "Factory Method" එක වගේ වැඩ කරන්නේ.
මෙන්න සරල උදාහරණයක්:
public class Logger {
// 1. Static instance of the class
private static Logger instance;
// 2. Private constructor to prevent direct instantiation
private Logger() {
System.out.println("Logger instance created!");
}
// 3. Public static method to get the instance
public static Logger getInstance() {
if (instance == null) {
// Thread-safety consideration: In a multi-threaded environment,
// multiple threads might try to create an instance simultaneously.
// This simple check is not thread-safe.
instance = new Logger();
}
return instance;
}
public void log(String message) {
System.out.println("Log message: " + message);
}
}
මේක පාවිච්චි කරන විදිය:
public class Application {
public static void main(String[] args) {
Logger logger1 = Logger.getInstance();
logger1.log("First log message");
Logger logger2 = Logger.getInstance();
logger2.log("Second log message");
// Both logger1 and logger2 refer to the same instance
System.out.println("Are both logger instances the same? " + (logger1 == logger2));
}
}
මේ code එක run කරාම output එක මෙහෙම එයි:
Logger instance created!
Log message: First log message
Log message: Second log message
Are both logger instances the same? true
ඔයාලට පේනවා ඇති `Logger instance created!` කියලා message එක print වෙන්නේ එක පාරයි. ඒ කියන්නේ `Logger` class එකේ object එකක් හැදිලා තියෙන්නේ එකයි කියන එකයි. 😉
Thread-Safety ගැනත් හිතන්න ඕන 🤷♂️
උඩ තියෙන සරල Singleton implementation එක multi-threaded environment එකකදී ප්රශ්නයක් වෙන්න පුළුවන්. මොකද එකම වෙලාවේ thread දෙකක් getInstance()
method එකට access කරොත්, instance == null
කියන check එක දෙන්නටම true වෙලා, object instance දෙකක් හැදෙන්න ඉඩ තියෙනවා. මේක වළක්වාගන්න Synchronized methods, Double-Checked Locking වගේ techniques පාවිච්චි කරන්න පුළුවන්. හැබැයි Java 5 වලට පස්සේ Enum Singletons තමයි Singleton implement කරන්න තියෙන හොඳම, thread-safe සහ serialization safe විදිය. ඒ ගැන වෙන blog post එකකින් කතා කරමු.
Spring Framework එකේ Singleton 🌿
දැන් අපි බලමු Spring Framework එක Singleton Pattern එක manage කරන්නේ කොහොමද කියලා. Spring එකේදී, අපි define කරන Beans (Spring managed objects) default විදියට Singleton Scope එකේ තමයි තියෙන්නේ. ඒ කියන්නේ ඔයාලා Spring application එකක් run කරනකොට, Spring IOC Container එක Bean Definition එකකට අදාලව හදන්නේ එකම Bean instance එකයි. ඊට පස්සේ ඒ Bean එක ඕන වෙන හැම තැනකටම Inject කරන්නේ ඒ එකම instance එකයි.
උදාහරණයක් විදියට, ඔයාලා service class එකක් හදනවා නම්:
@Service
public class UserService {
public UserService() {
System.out.println("UserService bean created!");
}
public User getUserById(Long id) {
// ... logic to fetch user
return new User(id, "John Doe");
}
}
මේ UserService
එක Application එකේ ඕනෑම තැනක @Autowired
කරනකොට, Spring එකෙන් Inject කරන්නේ එකම UserService
instance එකයි.
ඔයාලට අවශ්ය නම්, Bean එකක scope එක explicitly define කරන්නත් පුළුවන්. මේකට @Scope
annotation එක පාවිච්චි කරනවා:
@Service
@Scope("singleton") // This is the default, so explicitly stating it is optional
public class ProductService {
public ProductService() {
System.out.println("ProductService bean created!");
}
public Product getProduct(String name) {
// ...
return new Product(name);
}
}
@Scope("singleton")
කියන එක default නිසා සාමාන්යයෙන් ලියන්නේ නැහැ. හැබැයි ඔයාලට හැම request එකකටම අලුත් instance එකක් ඕන නම් @Scope("prototype")
පාවිච්චි කරන්න පුළුවන්. ඒක ගැනත් වෙන blog post එකකින් කතා කරන්නම්.
Spring වලදී Singleton Beans ගොඩක්ම පාවිච්චි කරන්නේ Stateless Beans වලට. ඒ කියන්නේ ඒ Beans වලට වෙනස් වෙන data (state) එකක් නැති, එකම විදියට හැම වෙලාවෙම වැඩ කරන methods විතරක් තියෙන Beans වලට. Controller, Service, Repository classes ගොඩක් වෙලාවට Stateless Singleton Beans තමයි.
Singleton පාවිච්චි කළ යුත්තේ කවදාද? / නොකළ යුත්තේ කවදාද? ⚠️
ඕනෑම Design Pattern එකක් වගේම Singleton Pattern එකටත් තියෙනවා යම් යම් සීමාවන් සහ පාවිච්චි නොකළ යුතු අවස්ථා.
පාවිච්චි කළ යුතු අවස්ථා:
- Logging: Application එකේ හැමතැනකින්ම log කරන්න ඕන වුණාම එකම Logger instance එකක් පාවිච්චි කරන එක හොඳයි.
- Configuration Manager: Application එකට අදාල settings load කරලා හැමතැනටම provide කරන්න එකම config manager එකක් පාවිච්චි කරනවා.
- Cache Manager: Data caching වලට.
- Thread Pool: Thread pools manage කරන්න.
- Driver objects: Database driver වගේ දේවල් manage කරන්න.
පාවිච්චි නොකළ යුතු අවස්ථා (Cons):
- Global State Issues: Singleton එකක state (වෙනස් වෙන data) තියෙනවා නම්, multi-threaded environment එකකදී ඒ state එක manage කරන එක ගොඩක් අමාරු වෙනවා. Race conditions, deadlocks වගේ ප්රශ්න එන්න පුළුවන්. ඒ නිසා Singleton හැමවිටම Stateless වෙන්න ඕන.
- Testing Difficulties: Singleton classes test කරන එක අමාරුයි. මොකද එකම instance එකක් තියෙන නිසා, එක test එකක වෙනස් කරපු state එකක් ඊළඟ test එකට බලපාන්න පුළුවන්. මේක test isolation වලට බලපානවා.
- Hides Dependencies: Singleton එකක් use කරනකොට dependency injection වගේ patterns වලින් ලැබෙන benefits නැතිවෙන්න පුළුවන්. Code එකේ coupling එක වැඩිවෙන්න පුළුවන්.
- Scalability: Distributed systems වලදී Singleton එකක් maintain කරන එක අමාරුයි. Microservices environment එකකදී මේක තවත් සංකීර්ණ වෙනවා.
මතක තියාගන්න, Spring Framework එකේ Singleton Beans වලදී, Spring IOC container එක තමයි මේවා manage කරන්නේ. ඒ නිසා සාමාන්ය Java Singleton එකක් හදනවට වඩා Spring වල Singleton managing එක ටිකක් වෙනස්. Spring ඒ හැම Bean එකක්ම IOC Container එක ඇතුලෙම maintain කරන නිසා, අපිට ඒ ගැන වැඩිය හිතන්න ඕන නැහැ.
ඔබේ Application එකේ Singleton භාවිතය විශ්ලේෂණය කරමු! (Practical Exercise) 📊
දැන් ඔයාලා Singleton Pattern එක ගැන ටිකක් තේරුම් අරගෙන ඇති කියලා හිතනවා. මෙන්න ඔයාලට කරන්න පුළුවන් පොඩි exercise එකක්:
- ඔයාලගේ පරණ Spring project එකක් (හෝ අලුත් එකක්) open කරලා බලන්න.
@Service
,@Repository
,@Controller
වගේ annotations වලින් define කරලා තියෙන Beans මොනවද කියලා identify කරන්න.- ඒ Beans වලට Scope එක define කරලා තියෙනවද බලන්න. (ගොඩක් වෙලාවට default Singleton scope එක නිසා define කරලා නැති වෙයි.)
- ඒ Beans අතරින් Stateful Beans (ඒ කියන්නේ instance variables වල data තියාගන්න, වෙනස් වෙන data තියාගන්න) මොනවද කියලා බලන්න. ඒ වගේ Beans Singleton scope එකේ තිබීමෙන් ඇතිවෙන්න පුළුවන් ප්රශ්න ගැන හිතන්න. (Hint: Thread-safety issues)
- ඔයාලගේ Application එකේ Singleton instance එකක් විදියට පාවිච්චි කරන්න හොඳ class මොනවද කියලා identify කරන්න. (උදා: configuration readers, utility classes).
මේ exercise එකෙන් ඔයාලට Singleton Pattern එක practically තේරුම් ගන්න ලොකු උදව්වක් වෙයි. 🙌
අවසාන වශයෙන් 🏁
Singleton Design Pattern එක software development වලදී නිතරම භාවිත වන වැදගත් Pattern එකක්. Resources optimize කරගන්න, performance වැඩි කරගන්න, Global access point එකක් ලබාගන්න මේක ලොකු උදව්වක්. විශේෂයෙන්ම Spring Framework එක default විදියටම Singleton Beans manage කරන නිසා, ඒ ගැන හොඳ අවබෝධයක් තියෙන එක ඔයාලට ගොඩක් වටිනවා.
හැබැයි මතක තියාගන්න, Singleton එකක් පාවිච්චි කරනකොට stateless වෙන්න පුළුවන් තරම් බලන්න. එහෙම නැති වුණොත් concurrency issues, testing difficulties වගේ ප්රශ්න එන්න පුළුවන්. ඒ නිසා හැම Pattern එකක් වගේම Singleton එකත් තේරුම් අරගෙන, හරියට පාවිච්චි කරන්න!
මේ blog post එක ඔයාලට වැදගත් වෙන්න ඇති කියලා හිතනවා. ඔයාලගේ අදහස්, ප්රශ්න පහලින් comment කරන්න. 📝 ඒ වගේම මේ concepts ඔයාලගේ projects වලට implement කරලා බලන්න! Coding is all about practice! 💡