前述:

  在学习单例模式后,对老师课上布置的课后作业,自然要使用单例模式,但是不是一般的单例,要求引起我的兴趣,案例是用服务器。

  老师布置的要求是:服务器只有一个,但是使用这个服务器时候可以有多个对象(原版的)和备份数据库,也就是至少要两个对象,因为有可能服务器对象会垮掉,所以要用备份的,所以这里要考虑调用时候,应该返回哪个服务器对象,还有当服务器对象垮掉后,应该怎么处理,保证用户的使用。老师说,两个对象是基本要求,如果能够控制多个对象,分数更高哦。

  我觉得蛮有意思的题目,如果只考虑两个对象,无非在单例模式下原来是建立一个,现在改为建立两个,然后在使用前作检查,如果服务器垮掉,那备份服务器拿起来用,并且要给原版(原来垮掉的那个重新赋值)这样,有些简单。所以,我自己在琢磨后,写出了能够控制多个服务器的多例模式,并且保证只实例一次,后面的服务器对象都是备份原来的,并且返回的服务器对象都是可用。

首先,看下画类图

先看里面的字段: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服务器)的更多相关文章

  1. java设计模式—单例模式(包含单例的破坏)

    什么是单例模式? 保证一个了类仅有一个实例,并提供一个访问它的全局访问点. 单例模式的应用场景? 网站的计数器,一般也是采用单例模式实现,否则难以同步: Web应用的配置对象的读取,一般也应用单例模式 ...

  2. Java设计模式 - 单例模式详解(下)

    单例模式引发相关整理 关联线程安全 在多线程下,懒汉式会有一定修改.当两个线程在if(null == instance)语句阻塞的时候,可能由两个线程进入创建实例,从而返回了两个对象.对此,我们可以加 ...

  3. c++设计模式之单例模式下的实例自动销毁(垃圾自动回收器)

    关于C++单例模式下m_pinstance指向空间销毁问题,m_pInstance的手动销毁经常是一个头痛的问题,内存和资源泄露也是屡见不鲜,能否有一个方法,让实例自动释放. 解决方法就是定义一个内部 ...

  4. java设计模式——单例模式(一)

    一. 定义与类型 定义:保证一个类仅有一个实例,并提供一个全局访问点 类型:创建型 二. 适用场景 想确保任何情况下都绝对只用一个实例 三. 优缺点 优点: 在内存里只有一个实例,减少了内存开销 可以 ...

  5. 小菜学习设计模式(二)—单例(Singleton)模式

    前言 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Method) ...

  6. 设计模式 单例模式(Singleton) [ 转载2 ]

    设计模式 单例模式(Singleton) [ 转载2 ] @author java_my_life 单例模式的结构 单例模式的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类 ...

  7. 设计模式 单例模式(Singleton) [ 转载 ]

    设计模式 单例模式(Singleton) [ 转载 ] 转载请注明出处:http://cantellow.iteye.com/blog/838473 前言 懒汉:调用时才创建对象 饿汉:类初始化时就创 ...

  8. c#设计模式-单例模式(面试题)

    c#设计模式-单例模式 单例模式三种写法: 第一种最简单,但没有考虑线程安全,在多线程时可能会出问题, public class Singleton { private static Singleto ...

  9. 设计模式--单例模式(Singleton pattern)及应用

    单例模式 参考文档: 该文仅介绍spring的单例模式:spring 的单例模式 介绍原理:Spring的单例模式底层实现 参考书籍:漫谈设计模式:从面向对象开始-刘济华.pdf 1. 单例模式解析 ...

随机推荐

  1. [ActionScript 3.0] 处理xml内容换行时行间距较大问题的一种简单方法

    我们一定遇到过这种情况,在读取xml里的文章内容时,一旦有换行的位置在flash里显示出来的行间距会比较大,而并非我们想要的效果,解决这个问题的方法除了使用正则表达式以外,这里介绍一种比较简单的方法, ...

  2. CiSCO 交换机配置 SSH 登陆

    CiSCO 交换机配置 SSH 登陆 题目:在三层交换机上仅运行 SSH 服务,且用户名和密码的方式登录交换机. (一)了解主机名与域名 ​ 1."主机名" 为该设备的名称 ​ 2 ...

  3. Oracle中-事务-序列-视图-数据类型笔记

    事务(Transaction) 事务(Transaction)是一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位,是数据库环境中的逻辑工作单位. 事务是为了保证数据库的完整性 在o ...

  4. 神奇的树上启发式合并 (dsu on tree)

    参考资料 https://www.cnblogs.com/zhoushuyu/p/9069164.html https://www.cnblogs.com/candy99/p/dsuontree.ht ...

  5. [转] java获取hostIp和hostName

    [From] https://www.cnblogs.com/huluyisheng/p/6867370.html InetAddress的构造函数不是公开的(public),所以需要通过它提供的静态 ...

  6. lvm拉伸与快照

    一.拉伸 *用fdisk分区 *构建pv *将pv加入vg *将pv内的pe加入lv *通过resize将文件系统的容量增加 1.分区 [root@server3 ~]# fdisk /dev/vdb ...

  7. Emma姐

  8. 【linux】如何查看文件的创建、修改时间

    本篇博文旨在介绍Linux下查看文件时间的方法:并介绍如何使用touch指令来进行文件时间的创建以及修改 如何查看文件的时间信息利用stat指令查看文件信息 三种时间的介绍ATime ——文件的最近访 ...

  9. NEXIQ 125032 USB Link Diesel Truck Diagnose Interface Introduction

    What are the features of nexiq usb link? 1.Compatible with applications that diagnose engines, trans ...

  10. MonggoDB学习笔记

    MongoDB MongoDB介绍:非关系型的文档数据库.MongoDB的数据模型是面向文档的,文档是一种类似于JSON的结构.简单理解MongoDB这个数据库中存的是各种各样的JSON.(BSON) ...