建立一个「唯一」物件,专责於服务只能单一连线的情境,例如跟资料库的沟通,同时确保全域内都可以呼叫该物件。
Singleton 是相当好懂的模式,用在只能服务单一连线的情境下,避免多重连线产生时间差,导致执行完毕的结果不是我们要的,例如:
相关作法是:
getInstance()
,负责回传 instance
,让全域都可以呼叫并使用。Java
因为可以跑多的执行绪(Thread
),所以在 getInstance()
除了原有的锁之外还要多加两道锁:
instance
是否存在?instance
是否存在?至於 JavaScript
,不能使用常见的 class
写法,而是使用 IIFEs(Immediately Invoked Functions Expressions),让物件只会建立一次,没有其他建立的方法。
Singleton: EmergencyTelephone
public class EmergencyTelephone {
private static EmergencyTelephone instance;
private EmergencyTelephone() {
}
private void useTelephone(String phoneNumber) {
System.out.println("(号码:" + phoneNumber + ")拿起话筒");
System.out.println("(号码:" + phoneNumber + ")输入号码");
System.out.println("(号码:" + phoneNumber + ")等待接通");
System.out.println("(号码:" + phoneNumber + ")确认电话已经打通");
}
private void tellDetails(String phoneNumber) {
System.out.println("(号码:" + phoneNumber + ")详述情况");
System.out.println("(号码:" + phoneNumber + ")告知地点");
System.out.println("(号码:" + phoneNumber + ")记录指示");
}
private void finishTelephoneTalk(String phoneNumber) {
System.out.println("(号码:" + phoneNumber + ")挂上电话");
System.out.println("(号码:" + phoneNumber + ")思考指示");
System.out.println("(号码:" + phoneNumber + ")行动");
}
public synchronized void execute(String phoneNumber) {
useTelephone(phoneNumber);
tellDetails(phoneNumber);
finishTelephoneTalk(phoneNumber);
}
public static EmergencyTelephone getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new EmergencyTelephone();
}
}
}
return instance;
}
}
进行测试
public class EmergencyTelephoneSample extends Thread {
String phoneNumber;
public EmergencyTelephoneSample(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public void run() {
EmergencyTelephone emergencyTelephone = EmergencyTelephone.getInstance();
if (emergencyTelephone != null) {
System.out.println("这通电话号码是:" + phoneNumber + ",这台电话的生产序号是:" + emergencyTelephone.hashCode());
emergencyTelephone.execute(phoneNumber);
}
}
public static void main(String[] args) {
EmergencyTelephone emergencyTelephone1 = EmergencyTelephone.getInstance();
EmergencyTelephone emergencyTelephone2 = EmergencyTelephone.getInstance();
if (emergencyTelephone1.hashCode() == emergencyTelephone2.hashCode()) {
System.out.println("两个是同一个物件");
}
Thread t1 = new EmergencyTelephoneSample("119");
Thread t2 = new EmergencyTelephoneSample("110");
t1.start();
t2.start();
}
}
Singleton: EmergencyTelephone
const EmergencyTelephone = (() => {
let instance = null;
function initialize() {
let hashCode = Math.floor(Math.random() * 10000000);
function useTelephone(phoneNumber) {
console.log("(号码:" + phoneNumber + ")拿起话筒");
console.log("(号码:" + phoneNumber + ")输入号码");
console.log("(号码:" + phoneNumber + ")等待接通");
console.log("(号码:" + phoneNumber + ")确认电话已经打通");
}
function tellDetails(phoneNumber) {
console.log("(号码:" + phoneNumber + ")详述情况");
console.log("(号码:" + phoneNumber + ")告知地点");
console.log("(号码:" + phoneNumber + ")记录指示");
}
function finishTelephoneTalk(phoneNumber) {
console.log("(号码:" + phoneNumber + ")挂上电话");
console.log("(号码:" + phoneNumber + ")思考指示");
console.log("(号码:" + phoneNumber + ")行动");
}
return {
execute: function (phoneNumber) {
useTelephone(phoneNumber);
tellDetails(phoneNumber);
finishTelephoneTalk(phoneNumber);
},
getHashCode: function () {
return hashCode;
}
};
}
return {
getInstance: function () {
if (instance === null) {
instance = initialize();
}
return instance;
}
}
})();
进行测试
const emergencyTelephoneSample = () => {
const emergencyTelephone1 = EmergencyTelephone.getInstance();
const emergencyTelephone2 = EmergencyTelephone.getInstance();
if (emergencyTelephone1.getHashCode() === emergencyTelephone2.getHashCode()) {
console.log("两个是同一个物件");
} else {
console.log("出问题,两个不是同一个物件");
}
console.log("进行第一通电话拨打");
const phoneNumber1 = "119";
console.log("这通电话号码是:" + phoneNumber1 + ",这台电话的生产序号是:" + emergencyTelephone1.getHashCode());
emergencyTelephone1.execute(phoneNumber1);
console.log("进行第二通电话拨打");
const phoneNumber2 = "110";
console.log("这通电话号码是:" + phoneNumber2 + ",这台电话的生产序号是:" + emergencyTelephone2.getHashCode());
emergencyTelephone2.execute(phoneNumber2);
}
emergencyTelephoneSample();
Singleton 是非常容易理解的模式,也是十分常见的模式。
要注意的反倒是语言特性,不同语言执行上有细节,例如执行绪的多寡,将影响 Singleton 的效果,这点唯有加强自身对该语言的熟练才能避免。
这是最後一篇 Creational patterns,明天将进入下个类别:Structural patterns 的第一个模式:Adapter 模式。
>>: [Tableau Public] day 25:台湾姓氏分布分析-3
-安全和隐私控制系列(来源:NIST SP 800-53 R5) .安全和隐私控制有效性解决了正确...
当我们训练模型需要部署在硬体较为受限的智慧型装置、IOT设备,模型运算在吃紧的硬体资源中显得笨重,...
分治法(Divide and conquer) 又称分而治之法,是最常被使用的策略方式,原理是将一个...
年中才刚攻破 JavaScript 30 挑战一天一题 JavaScript,过不久因缘际会接了一个...
以前很菜的时候收过这个需求 真心很讨厌PDF,因为要自己算座标和设定一堆东西 後来这个需求就被弃置了...