(本节讲述的知识点,有像更新,一个变化,另一个也同时变化)
一.
接下来是比较重要的一部分知识点-设计模式。
设计模式的定义,从字面来看就是设计时的统一规范。
java有23种设计模式,也可以用于C++,因为这是一种思想,在面向对象的语言里都是通用的。
强调的是解决问题的思想,不拘泥于任何一种具体的计算机语言。
设计模式的核心在于:为了解决问题,设计了方法,并且不断地改进这个方法,最终得到一个非常合适高效的解决方法。
对于23种设计模式,我们今天讨论其中的一种,单例设计模式。
学习设计模式要注意一点,设计模式是为了解决什么问题。知道了解决什么问题,自然也就知道了什么时候用。
二.
一个类在内存里面只有一个对象,单例是指单个实例。
这种设计模式的名称有好多种,不要被名称所欺骗。重点在于保证类的对象唯一性。我们什么时候需要类在内存中,只有一个对象呢?
单例设计模式要注意的就是两点:什么时候要保证类的对象唯一性?怎么来保证类的对象的唯一性?
现在举例介绍单例设计模式:
这有两个应用程序A和B,它们都会用到一个配置信息。比如说这里面有一些信息,num,age,name....
为了操作这些信息方便,我们通常都把这些信息封装在对象当中。我找到了这些对象,就意味着我找到了这些信息。
我们把这个称之为,能封装信息的配置文件。(配置文件和对象之间是什么关系?对象只能封装数据是么?)
A想操作这些信息,就要在A中创建一个配置文件对象,甭管什么配置信息,就是对象嘛。为什么呢?信息多了,都要进行封装,我们想操作信息,必须先找对象。A想操作配置文件里的信息,要先建立对象,然后,再调用ConfigFile里面的方法。操作完以后,A可能对ConfigFile里面的信息进行了改变。比如,A把num1赋值为了10。(我感觉这里面有点混乱。如果对象是放置在A中的,那么后面说的A对ConfigFile里面的信息进行改变,怎么可能?因为这里ConfigFile配置文件感觉像是描述类,里面的成员变量怎么发生变化?)
接下来,B程序也想操作配置文件中的信息。(ConfigFile的出现像是一个描述类,A和B怎么都会想着改变?)
按照上面的思路,B中也要创建一个对象,谁要操作信息,谁就创建对象。
但是,我们希望它们共用一个配置信息。A如果对ConfigFile进行操作的话,B要知道。简单点来说,A将ConfigFile中的num1从1改为了10,B在操作num1的时候,必须知道它是10。
(这里开始解惑) A创建一个ConfigFile配置文件的对象,new ConfigFile(); 里面就有一组配置信息,B也在它自己的空间创建一个ConfigFile配置文件的对象后,它就有了一组新的配置信息,两者互不相关。所以,A对自己的配置信息改完以后,和B是没有关系的。→这从里才看出前面知识点的影子。
两个相同类类型的对象,本来封装的数据互不相关,但是现在希望两者产生联系。
这是我们讨厌的地方,我们希望两者实现共享。
实现方法,将配置文件ConfigFile中的信息全部变成静态,就可以了(为什么?)。但是这里面数据信息量很多,全静态化,会导致生命周期过长(和类一起加载在方法区,存储时间比较长,使得生命周期长)。既然我们用的是同一个对象(这里说的同一个对象是怎么操作的,是创建两个互相关联的对象么?),我只要这个类(这个类,说的就是ConfigFile)和对象是唯一的(就是说该类只产生一个对象,那么谁调用,都是这个,限制对象个数。),那么A和B用的就是同一个。而且,对象的生命周期相对而言,短一些,不用的时候,可以变垃圾。这个时候,我们就只要保证A和B用到的,配置文件对象是同一个,就搞定了。怎么解决这个问题呢?
(到目前为止,有一些谈论的是和前面的知识点相联系的,但还有相当一部分是和原先的理论体系是不一样的)
现在有人对这个问题,提出了解决方案,我们直接拿来使用就可以了。我们不用他提供的方案,我们也可以自己写。完全可以,设计模式本身就是对我们面向对象语言中产生的问题进行优化。设计模式是一种固定好的解决问题的方式,不采用也可以。
观看这个例子,我们知道,A中不能new一个对象,因为如果能用对象的话,A一新建,对象就会跑到A中,所以就不能再new新建了。(如果一个类要是能new对象,对方程序可以new,n多个出来,就不能保证对象的唯一性。)因此,第一步就是不让A来new对象,因为一旦新建对象了,就不可控了。
不允许new,那就导致没对象,为了保证唯一性,是不是还得有一个?现在不让new,那么那唯一的一个在哪?
我让你new,我不能控制,但是我来new,就可以I控制。
1的好处就是避免产生更多对象,对象一多容易出错。
2,不让new就安全了,但这麻烦了,你不让我new,我就没对象,说是保证唯一性,那还得有一个,你不让我new,那一个跑哪去了?我不让你new,我来new。这里产生了变化,不让你new,我来new,我可以进行控制,new一个就完事了。要保证单例,new一个就可以了。
3. 创建完本类实例后,要提供出去,给别人用。
就上面三步就能把单例这个动作做完。换句话说,用这三步,就能解决这个类的对象唯一性。接下来,这三步怎么去实现啊?
步骤:
1. 私有化该类的构造函数。有几个私有化几个,都不向外提供。(怎么就能实现不让对方,创建我的对象呢?不让初始化就可以)
2. 通过new在本类中,创建一个本类的对象。
3. 定义一个公有的方法,将创建的对象返回。(这说明是有返回值,是一个对象,本类类型的对象)
上面的Single类中三步写完了,紧跟着要用一下。我们怎么调用getInstance的方法呢?我们得创建一个对象调用,
new Single().getInstance(); 这么写就废了。因为在其他存类当中不能创建该类的对象,因为它被私有化了,因此new不成。但是getInstance()方法是非静态的,如果不能够new对象,这方法就不能调用(这句话是说,非静态的方法必须是对象调用的。如果没有对象,那就没法调用。类只能调用静态方法)。既然,不能创建对象,我们还要获取对象(这话说的挺奇怪的,和后面的语句完全无关),这个方法要被调用的话,有两种方法,第一个是对象调用,第二个是类名调用,但是类名调用有前提,必须是静态(在getInstance方法前加上static修饰),而静态访问的内容必须是静态的(在本类对象前要用static修饰)。因此,在主函数中,写上Single.getInstance();就可以调用这个方法了,这个方法返回来一个s,s里面持有一个地址。所以在这里面可以写上一个Single ss=Single.getInstance(); 这样,我就拿到了这个类的实例(主函数中用变量ss来承接s的对象地址编码)。→其实,思考下来也不难。不允许创建对象,只能使用唯一的对象。大家仔细回想一下,局部变量和所指向的对象在内存中分布图。如果可以创建对象的话,那就是多个一对一的分布。但是这里是禁止创建对象的,只允许特定的类中有一个固定的对象,只能通过多个引用变量指向同一对象来解决问题。特定的类必须要提供将对象地址提供出来的方法,来方便调用。下面截图中的s有多种名称,可以是静态变量,Single类类型的引用变量,以及对象。
Single.getInstance(),类名调用本类静态方法,返回给对方程序一个对象。没法创建,但是可以通过方法提供出来。
说白了,这个s指向new Single()这个对象,ss指向的还是这个对象。
这么写有一个疑问,s是不是Single类中的成员变量?s是定义在类中的,如果加一个int x=4; x就是成员变量,凡是定义在类中的都是(在这里,对于成员变量和静态变量的分解模糊起来。这说明什么?两者的分界,没有想像的那么清楚)。x是基本数据类型,s是引用数据类型。s本身就是成员,
如果是成员,直接来个Single.s可以么?貌似可以,是成员么?是静态么?能通过类名直接调用么?是。
调用完了,书写的格式如下所示。这里Single后面的一个点号,就拿到了s,换句话说,就拿到了s所持有的对象地址,并把这个地址赋值给了ss,ss也就指向了这个对象。
为什么要这么做呢?如果这么能做的话,那调用方法还有什么用,说的是调用getInstance()方法,只是调用了对象,干嘛要写一个方法,那我们搞这个方法还有什么用?
分析:开始,我们在类中定义变量,要写get和set方法,
如果将方法消去的话,会不可控,方法后面接有参数。以下图的String name为例,当给定特定的名称时,就返回s,当不符合名称时,就不返回。谁说对象给你用,单例是单例,满足需求才给你用,不满足需求不给用。这叫可控,这是之前讲过的上锁。
s是成员变量,一般我们是不会把成员变量暴露出去,是为了可控,所以加上private。私有的作用是什么,怎么用?
这里判别是否是同一对象。这里我想问的是,为什么输出语句还能有一个运算的功能?
按照题目所讲述的来看,只要做到描述类中的三句话,就可以得到对象的唯一性,
现在我们想保证test类在内存中的对象唯一性。
在原有基础上加了三步动作,
原文:http://www.cnblogs.com/wsw-bk/p/7685096.html