本题来自:http://blog.youkuaiyun.com/v_july_v/article/details/11921021
题目描述:请设计一个排队系统,能够让每个进入队伍的用户都能看到自己再队列中所处的位置和变化,队伍可能随时有人加入和退出,当有人退出影响到用户的位置排名时需要及时反馈到用户。
先在对本题进行做如下假设:
1.不存在插队的情况,即新用户只能出现在队伍的末尾
2.本次设计未满足随时有人加入和退出条件,即未满足同一时刻的并发处理
那么对题目进行分析:
第一,用户的关注点有两个:所处位置以及位置是否变化
第二,导致位置的变化是由用户退出所引起的
那么,根据上述的描述,如果让我来作答,会选择设计模式中的Observer(观察者模型)来作答。因为,此场景是一种订阅-推送的场景,可以参考之前我对Observer描述:http://blog.youkuaiyun.com/anger_coder/article/details/12292979
那么基于此,分析观察者模式中的角色:
观察者:用户
抽象主题:加入、退出
解释说来,就是用户作为观察者,只关注于自己的位置是否发生变化,这个变化的通知者——系统;那么系统则关心抽象主题,也就是加入、退出。实现的流程就是:观察者加入到系统中,当有关注的事件发生时,系统通知观察者。
下面来看下类图
上述就是实现Observer模型的类定义,按照此思路实现示例Demo(Java版):源码下载地址:TecentObserver
关键代码如下:
package com.hzy.observer;
public interface Observer
{
/**
*
* @param eventId
* |-- 1代表 登入
* |-- 2代表退出
*/
public void Update( int eventId, ConcreteSubject concreteSubject ); //观察者用于更新自身状态
}
package com.hzy.observer;
public interface Subject
{
//将观察者添加到目标事件
public void Attach( Observer observer );
//将观察者从目标事件解除
public void Detach( Observer observer, int index );
//事件通知观察者
public void Notify();
}
package com.hzy.observer;
public class ConcreteObserver implements Observer
{
private String name;
private int id;
public ConcreteObserver( String name )
{
this.name = name;
}
@Override
public void Update( int eventId, ConcreteSubject concreteSubject )
{
switch( eventId )
{
//登录
case 1:
this.setId( concreteSubject.getAddId() );
System.out.println( this.getName() + " : " + id );
break;
//登出
case 2:
if ( this.getId() > concreteSubject.getLeaveId() )
{
this.setId( this.getId() - 1 );
System.out.println( this.getName() + " :" + "My Position Has Changed, after change is " + this.getId() );
}
break;
}
}
protected void setId( int id )
{
this.id = id;
}
protected int getId()
{
return this.id;
}
protected String getName()
{
return this.name;
}
}
package com.hzy.observer;
import java.util.Enumeration;
import java.util.Vector;
public class ConcreteSubject implements Subject
{
static private Vector<Observer> vector;
private int leaveId;
private int addId;
static{
vector = new Vector<Observer>();
}
/**
*
* 当通过Attach添加新人的时候 需要进行通知
* */
@Override
public void Attach( Observer observer )
{
// TODO Auto-generated method stub
this.setAddId( vector.size() );
observer.Update( 1, this );
vector.add( observer );
}
@Override
public void Detach( Observer observer, int index )
{
// TODO Auto-generated method stub
vector.remove( index - 1 );
// System.out.println( "After Remove Size: " + vector.size() );
this.setLeaveId( index - 1 );
this.Notify();
}
@Override
public void Notify()
{
// TODO Auto-generated method stub
Enumeration<Observer> e = vector.elements();
while( e.hasMoreElements() )
{
e.nextElement().Update( 2, this );
}
}
protected void setAddId( int addId )
{
this.addId = addId;
}
protected int getAddId( )
{
return this.addId;
}
protected void setLeaveId( int leaveId )
{
this.addId = leaveId;
}
protected int getLeaveId( )
{
return this.leaveId;
}
}
运行测试代码:
首先加入三名用户,分别为A、B、C;而后B用户退出,C用户的位置会发生改变,再加入新用户Join,结果如下图:
测试类代码:
package com.hzy.test;
import org.junit.Test;
import com.hzy.observer.ConcreteObserver;
import com.hzy.observer.ConcreteSubject;
public class TecentTest
{
@Test
public void test()
{
ConcreteSubject concreteSubject = new ConcreteSubject();
ConcreteObserver concreteObserverOne = new ConcreteObserver( "A" );
ConcreteObserver concreteObserverTwo = new ConcreteObserver( "B" );
ConcreteObserver concreteObserverThree = new ConcreteObserver( "C" );
ConcreteObserver concreteObserverJoin = new ConcreteObserver( "Join" );
concreteSubject.Attach( concreteObserverOne );
concreteSubject.Attach( concreteObserverTwo );
concreteSubject.Attach( concreteObserverThree );
concreteSubject.Detach( concreteObserverTwo, 2 );
concreteSubject.Attach( concreteObserverJoin );
}
}
思路就写到这里,附带了一个简单的实现,还有很多不完善的地方,如果思路不对,或者有其他好想法,希望大家踊跃发言,集思广益嘛!!:)