设计模式-单例模式下对多例的思考(案例:Server服务器)
前述:
在学习单例模式后,对老师课上布置的课后作业,自然要使用单例模式,但是不是一般的单例,要求引起我的兴趣,案例是用服务器。
老师布置的要求是:服务器只有一个,但是使用这个服务器时候可以有多个对象(原版的)和备份数据库,也就是至少要两个对象,因为有可能服务器对象会垮掉,所以要用备份的,所以这里要考虑调用时候,应该返回哪个服务器对象,还有当服务器对象垮掉后,应该怎么处理,保证用户的使用。老师说,两个对象是基本要求,如果能够控制多个对象,分数更高哦。
我觉得蛮有意思的题目,如果只考虑两个对象,无非在单例模式下原来是建立一个,现在改为建立两个,然后在使用前作检查,如果服务器垮掉,那备份服务器拿起来用,并且要给原版(原来垮掉的那个重新赋值)这样,有些简单。所以,我自己在琢磨后,写出了能够控制多个服务器的多例模式,并且保证只实例一次,后面的服务器对象都是备份原来的,并且返回的服务器对象都是可用。
首先,看下画类图
先看里面的字段:list就是多例保存的服务器实例;COUNT是常量,用于保存设置服务器的最大数量;使用时候是按队列取,因此top自然放的是list的顶部;name是服务器名,state来模拟服务器是否垮掉(true代表能用,false代表垮掉);CTIME是来计数器,来定时清理队列中不可用的服务器;time就是配合CTIME使用。
分析下设计的思路:其实最难的就是怎么获取服务器,还有怎么创建,获取,及删除无用的服务器,就是在静态方法getInstance方法里。
首先,调用cleanServer()方法,里面会检查有没有到计数值,如果有到,就执行将所有的遍历一遍,将不能用的服务器从队列里删除掉,这个是为了队列里面在top之前可能有获取不到的无用服务器,但是这些又不影响当前使用,所以可以用个计数器来进行清理。
第二步,用户获取服务器时候,先要使用一个循环,只要直到队列top到底了或者里某个服务器对象的state为true就跳出循环。这里只是为了找到可用的服务器,不需要遍历所有,可以节省了时间。
第三步,当跳出循环后,就判断队列有没有超过COUNT的值,
当没有等于COUNT值,那就执行createServer()方法,这里面存放创建或者是复制服务器;
当队列为空时候,就创建服务器,将当前服务器添加到队列里,并返回给用户;
如果不为空,就克隆上个能使用的服务器,并将当前复制的服务器添加到队列里,并返回给用户;
当等于COUNT值了,就把服务器直接返回。
好了思路分析完了,这样子多例是不是很好,可以对多个实例进行控制,为了测试,里面设置了Dispose()用来修改state值,模拟服务器不能使用了。
接下来贴代码,是使用java写的,其实我觉得算法的话,与实际的语言无关,只不过老师只认java,所以用java来写,其中使用了java的克隆模式,如果不了解,先去了解下,也是简单的。
import java.awt.List;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList; public class ServerStation implements Serializable {
//服务器多例list
static ArrayList<ServerStation> list = new ArrayList<ServerStation>();
//控制数量
static final int COUNT = 2;
//指向列表头服务器
static int top = -1;
//服务器名
String name;
//服务器状态
boolean state;
//计数器最大值
static final int CTIME = 5;
//计数器
static int time = 0;
//私有构造函数
private ServerStation(String name){
this.name = name;
this.state = true;
}
//设置服务器名
private void setName(String name){
this.name = name;
}
//获取服务器名
public String getName(){
return this.name;
}
//获取服务器状态
public boolean getState(){
return this.state;
} //显示服务器信息
public void showInfo(){
System.out.println("服务器名:"+this.name);
System.out.println("服务运行状态:"+this.state);
}
//释放服务器
public void Dispose(){
this.list.get(top).state = false;
}
//获取服务器
public static ServerStation getInstance(){
clearServer();
ServerStation server = null; while(top >= 0 && list.get(top).state == false)
removeServer(); if(top < COUNT - 1)
server = createServer();
else
server = getServer(); return server;
} //创建服务器或者克隆服务器
private static ServerStation createServer(){
ServerStation server = null;
if(top == -1){
top++;
server = new ServerStation("新服务器");
list.add(server);
}else{
server = cloneServer();
}
return server;
}
//获取服务器
private static ServerStation getServer(){
ServerStation server = list.get(top);
String name = server.getName();
if(name.contains("新"))
name = name.replace("新", "旧");
server.setName(name);
return server;
}
//清除无用服务器
private static void clearServer(){
if(time < CTIME){
time++;
return;
}
time = 0;
for(int i = 0;i<list.size()-1;i++){
if(list.get(i).getState() == false){
list.remove(i);
top--;
}
}
} //移除服务器
private static void removeServer(){
list.remove(top);
top--;
} //克隆服务器
private static ServerStation cloneServer(){
ServerStation server = null;
try{
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(list.get(top));
top++;
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(in);
server = (ServerStation)ois.readObject();
String name = server.getName();
if(!name.contains("备份")){
name = "备份"+name;
}
server.setName(name);
list.add(server);
oos.close();
ois.close();
}catch(Exception e){
e.printStackTrace();
System.out.print("错误");
} return server;
}
}
测试代码:
public class Main {
public static void main(String[] args) {
ServerStation s1 = ServerStation.getInstance();
s1.showInfo();
ServerStation s2 = ServerStation.getInstance();
s2.showInfo();
s2.Dispose();
ServerStation s3 = ServerStation.getInstance();
s3.showInfo();
s2.Dispose();
ServerStation s4 = ServerStation.getInstance();
s4.showInfo();
ServerStation s5 = ServerStation.getInstance();
s4.showInfo();
}
}
上边就是为了模拟,运行后验证,返回服务器都是可用的,蛮不错。
运行结果:
服务器名:新服务器
服务运行状态:true
服务器名:备份新服务器
服务运行状态:true
服务器名:备份新服务器
服务运行状态:true
服务器名:备份新服务器
服务运行状态:true
服务器名:备份旧服务器
服务运行状态:true
设计模式-单例模式下对多例的思考(案例:Server服务器)的更多相关文章
- java设计模式—单例模式(包含单例的破坏)
什么是单例模式? 保证一个了类仅有一个实例,并提供一个访问它的全局访问点. 单例模式的应用场景? 网站的计数器,一般也是采用单例模式实现,否则难以同步: Web应用的配置对象的读取,一般也应用单例模式 ...
- Java设计模式 - 单例模式详解(下)
单例模式引发相关整理 关联线程安全 在多线程下,懒汉式会有一定修改.当两个线程在if(null == instance)语句阻塞的时候,可能由两个线程进入创建实例,从而返回了两个对象.对此,我们可以加 ...
- c++设计模式之单例模式下的实例自动销毁(垃圾自动回收器)
关于C++单例模式下m_pinstance指向空间销毁问题,m_pInstance的手动销毁经常是一个头痛的问题,内存和资源泄露也是屡见不鲜,能否有一个方法,让实例自动释放. 解决方法就是定义一个内部 ...
- java设计模式——单例模式(一)
一. 定义与类型 定义:保证一个类仅有一个实例,并提供一个全局访问点 类型:创建型 二. 适用场景 想确保任何情况下都绝对只用一个实例 三. 优缺点 优点: 在内存里只有一个实例,减少了内存开销 可以 ...
- 小菜学习设计模式(二)—单例(Singleton)模式
前言 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Method) ...
- 设计模式 单例模式(Singleton) [ 转载2 ]
设计模式 单例模式(Singleton) [ 转载2 ] @author java_my_life 单例模式的结构 单例模式的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类 ...
- 设计模式 单例模式(Singleton) [ 转载 ]
设计模式 单例模式(Singleton) [ 转载 ] 转载请注明出处:http://cantellow.iteye.com/blog/838473 前言 懒汉:调用时才创建对象 饿汉:类初始化时就创 ...
- c#设计模式-单例模式(面试题)
c#设计模式-单例模式 单例模式三种写法: 第一种最简单,但没有考虑线程安全,在多线程时可能会出问题, public class Singleton { private static Singleto ...
- 设计模式--单例模式(Singleton pattern)及应用
单例模式 参考文档: 该文仅介绍spring的单例模式:spring 的单例模式 介绍原理:Spring的单例模式底层实现 参考书籍:漫谈设计模式:从面向对象开始-刘济华.pdf 1. 单例模式解析 ...
随机推荐
- 四,Smarty模板技术/引擎-----内建函数
内建函数是smarty提供的函数,不允许修改,只能被调用: 自定义函数是自己编写函数,注册成为smarty的函数,之后可以被调用. PHP的自建函数很多,讲解下<foreach>和< ...
- NFS共享服务
一.网络文件系统共享服务 NFS( Network File System,网络文件系统 )是一种基于TCP/IP传输的网络文件系统协议,最初由SUN公司开发,通过使用NFS协议,客户机可以像访问本地 ...
- replace函数结合正则表达式实现转化成驼峰与转化成连接字符串的方法
//连接符转成驼峰写法 function toCamel(str){ var reg=/-(\w)/g; return str.replace(reg,function(){ return argum ...
- OpenFire 安装及配置
下载 添加的属性为:EXE4J_JAVA_HOME,其属性的值为32位的JDK的所在位置. 2,openfire的启动路径中不能含有中文,好多java写的都是这个样. 3,如果安装的了 Jav ...
- jquery将json数据放入表格当中
数据: var datas = [{ name:"淘宝", url:"www.taobao.com", type:"购物网站" },{ na ...
- SpringBoot 启动的时候提示 Field *** in *** required a bean named 'entityManagerFactory' that could not be found.
错误截图 后面发现原来和入口类代码有关. //@SpringBootApplication(scanBasePackages = {"org.jzc.odata.cboard",& ...
- python(unittest)报告导出(一):使用HTMLTestRunner导出
(前提:HTMLTestRunner.py放在python安装目录的Lib文件夹下) 一般将HTMLTestRunner.py文件放入需要引用的目录下,但这个太过于局限,仅对当前项目有用,所以可以将H ...
- 高阶篇:4.4)FMEA手册的疑问与不足(个人观点)
本章目的:如题,述说FMEA手册第四版的疑问与不足. 1.前言 作者接触FMEA,并真正将其作为可靠性设计方法,也是在近几年的时候,所以不能说算是一个FMEA专家吧. 但作者也有一些自己的优势,就是自 ...
- POJ_2155 Matrix 【二维树状数组】
一.题面 POJ2155 二.分析 楼教主出的题,是二维树状数组非常好的题,还结合了开关问题(开关变化的次数如果为偶数,状态不变,奇数状态相反). 题意就是给了一个二维的坐标平面,每个点初始值都是0, ...
- Object-c 中的数据类型
导航: 基本类型 ID 对象类型常见的有 对象类型 -NSLog -NSNumber -NSString和NSMutableString -NSArray和NSMutableArray -NSSe ...