-
Notifications
You must be signed in to change notification settings - Fork 0
Description
单例模式
什么是单例模式,如何实现单例模式这个话题,网络上已经谈论的非常多了。我就不废话了,这里我谈谈我对单例模式的理解以及Java和JavaScript中的单例模式的不同。
下面是Java中实现单例模式的两种方法。
/**
* 饿汉式
*/
class BitFish{
private static BitFish bitfish = new BitFish();
private BitFish(){};
public static BitFish getInstance(){
return bitfish;
}
}
/**
* 懒汉式
*/
class SaltFish{
private static volatile SaltFish saltfish;
private SaltFish(){};
public static SaltFish getInstance(){
if (saltfish == null){
synchronized (SaltFish.class){
if (saltfish == null){
saltfish = new SaltFish();
}
}
}
return saltfish;
}
}
public class Test {
public static void main(String[] args) {
BitFish bitFish1 = BitFish.getInstance();
BitFish bitFish2 = BitFish.getInstance();
assert bitFish1 == bitFish2;
SaltFish saltFish1 = SaltFish.getInstance();
SaltFish saltFish2 = SaltFish.getInstance();
assert saltFish1 == saltFish2;
}
}单例模式在Java中的需求非常高,Spring框架解决的一个痛点就是通过IOC容器提供了单例模式的经典实现。
我觉这种需求主要原因是Java语言的设计特色。Java语言中,一切对象都是类的实例。我们编写的代码都以是一个个class文件的形式存在。
如果我们想创建一个对象,那么必须先要有类,然后通过类来实例化对象。
我家有只猫,名叫妙妙,它特别能吃。同时有一个其他猫不具有的能力:敲键盘,写代码!!不满你说,你现在看到的这段话,其实就是妙妙敲asdfqdfaeweal,miao m
那么现在问题来了,如果我想在java中创建一个妙妙对象,那么我要怎么做呢?
神说:必须先有类,才能有对象。
那么怎么写呢?妙妙是一只喵喵,所以我可以先写一个Cat类。
class Cat{
public String name;
public Cat(String name) {
this.name = name;
}
public void eat(){
System.out.println(name + " 又吃了一条鱼");
}
}
public class Test {
public static void main(String[] args) {
Cat miaomiao = new Cat("miaomiao");
}
}这可能是一个写法,但是问题来了,我们的妙妙和外面的妖艳贱货不同啊,它还能帮我敲代码adfwafe
这时候我们就必须扩展下Cat这个类,可能是这样的写法:
class MiaoMiao extends Cat{
public MiaoMiao(String name) {
super(name);
}
public void coding(){
System.out.println("I love coding");
}
}
public class Test {
public static void main(String[] args) {
MiaoMiao miaomiao = new MiaoMiao("miaomiao");
miaomiao.coding();
}
}这样是可以,但是问题又来了,我们的MiaoMiao类在逻辑上有什么意义吗?这个类的存在完全是为了我们的妙妙对象服务的。这是因为Java语法的限制,我们没办法绕过类来直接创建对象。我们凭空的写出了MiaoMiao这个逻辑上没有意义的类。同时我们这个类只应该有一个实例,毕竟妙妙是宇宙中唯一的一个个体。
其实这个问题在JavaScript中不存在,那么在JS中我们可以怎么写呢?
假设这是个Cat构造函数:
function Cat(name){
this.name = name;
}
Cat.prototype.eat = function(){
console.log(this.name + " 又吃了一条鱼");
}如果我们现在想创建一个妙妙,我们不需要编写一个MiaoMiao构造函数,我们直接使用对象字面量的写法就行了。
let miaomiao = {
name: "miaomiao",
coding(){
console.log("I love coding");
}
}当然同时我们还需要维护下正确的原型链
Object.setPrototypeOf(miaomiao, Cat.prototype)这样我们就创建了一个妙妙,完全没有一种所谓的MiaoMiao构造函数的生成。
我看过很多关于JS的设计模式的教程,很多教程都是把基于类的面对对象的单例模式拿到JS中来套用。我个人觉得这是完全没有必要的,JS是基于原型继承的,支持对象字面量写法,我们随手写的一个对象就是天然的单例。
其实这个问题在Java中很严重。我们知道软件工程毕竟是对现实世界的模拟,而在现实中,你、我、妙妙,都是独一无二的,不可复制的。所谓的类,就是对工厂函数的进一步抽象,提供了批量的创建对象的方式。
诚然,或许我们可以同一个Person类创建我这个对象,或者再准确点用Chinese类来创建我。但是无论多么细分,想要精准的描述我,只能为我单独的创建一个"MySelf"类,这样才能够足够准确的描述我,而这个"MySelf"类也只能有我这一个实例。这样也算是Java语言设计的一个副作用吧。
而在JS中,提供了对象字面量写法以及动态的修改对象的能力,不需要被类束缚。
上面就是我对单例模式的理解。