表达式:1 + 2 * 3
Expression = {literal | Expression}
interface Expression { int eval();}
子类 LiteralExpression, CompoundExpression,后者分运算符表达式OperatorExpresion,函数表达式FunctionExpression,运算符表达式又分单目双目
双目运算符表达式,有2个operand,类型是Expression
abstract class DoubleOperandExpression implments Expression{
Expression firstOperand;
Expression secondOperand;
public abstract operatorFunc(Expression a, Expresson b);
public int eval() {
return operatorFunc(first Operand, secondOperand);
}
}
class AddOperatorExpression extends DoubleOperandExpression {
public int operatorFunc(Expression a, Expression b) {
return a.eval() + b.eval();
}
}
机场调度系统
类:ControlTower, Plane, Schedule, Lane
关系:ContorlTower 和Lane以及Schedule都是一对多的关联关系,Schedule和Plane是一对一关系,Schedule 单向关联 Plane, Plane作为一个类,schedule不是它的固有属性。Plane对Lane有一对一的依赖关系(局部变量)
驱动控制:主动对象就是ControlTower,根据schedule顺序调度Plane,给Plane发命令消息
class ControlTower {
PriorityQueeue schedules;
Lane[] lanes;
Object signal = new Object();
public addSchedule(Schedule s) {
schedules.offer(s);
signal.notify();
}
public cancelSchedule(Schedule s) {schedules.remove(s);}
public void run() {
while (!airPort_shutdown) {
Schedule s = schedules.poll(); //bloked if no schedule
while (s.time > Now()) {
signal.wait(Now() - s.time);
if (s.time > schedules.peek().time) {
schedules.offer(s);
s = schedules.poll();
}
}
Lane lane = getFreeLane();
Plane plane = s.plane;
plane.moveTo(lane);
plane.takeOff();
releaseLane(lane);
}
}
public addSchedule(Schedule s) {schedules.offer(s);}
public cancelSchedule(Schedule s) {schedules.removde(s);}
}
类:Truck, 送货单,TrackingSystem, Log, DB
关系:Truck 一对多 送货单, TrackingSystem 一对多 Truck,一对一DB
消息交互:Truck 定时向 System发送 Log (TruckId, GPS, time), 后者SaveToDB
工作人员向system发送查询请求 List
驱动控制:Truck是一个主动对象:处理自己携带的送货单,直到处理完毕。
TrackingSystem:接受truck和 查询人员的查询消息,
4 21点游戏
庄家轮流问每个人要不要,直到所有人都不要,然后判断谁赢,然后下一次游戏。
类庄家Game21Points, Player
数据都封装在庄家类里
消息互动:庄家问Player要不要,庄家通知Player win
驱动控制:只有庄家是主动对象,单线程。
Class Game21Points {
boolean in[NUM_PLAYER];
int points[NUM_PLAYER];
Player players[NUM_PLAYER];
Deck deck;
void run () {
while (!closed) {
for (int player = 0; player < NUM_PLAYER; ++player) {
in[player] = true;
points[player] = 0;
}
int numOfIn = NUM_PLAYER;
deck.shuffle();
while(numOfIn > 0) {
for (int player = 0; i < NUM_PLAYER; ++player) {
if (in[player] == true) {
if (players[i].needMore()) {
points[player] += deck.next();
if (points[player] > 21) {
in[player] = false;
points[player] = 0;
--numOfIn;
}
}
else
in[player] == false;
}
}
}
judge();
}
}
void judge(){
int player = getMax(points);
player.win();
}
}
Cache
对象:Cache(服务接口类,也是(Mediator),Item(封装用户data)Index(负责查找data位置),Store,负责根据位置取出Item,再返回给用户。
interface Cache
interface Item
interface Index { Location getLocation(K key); void removeIndex(K key); void updateIndex(k key);}
interface Store { Item takeOut(Location pos); Item get(Location pos); void append(Item item) }
interface CacheWithExpireStategy {}
关于最精髓的LRU策略是封装到Store里还是由上层Cache类负责?原则是:单一责任。Store的责任就是简单的仓库管理操作,这样不同的过期策略只是建立在store上层的策略。整体中如果有部分是可变的,那么这个可变的部分就应该独立出来作为一个组件,每个组件都是不变的,单一行为的。可变的部分是通过多态实现,可以插拔不同组件,但是组件是不变的,对修改关闭。
Cache和不同策略啥关系,可以继承,比如LRUCache, LFUCache, 也可以委托(聚合) Cache委托内部封装的LRUStrategy去实际操作。这是经典泛化 vs 聚合的问题,前者是结构层面的,后者是动态的,也就是一个Cache可以支持不同的策略
凡是涉及数据管理的系统,都可以用图书馆来考虑,都要面临图书的位置查找和实际摆放两个问题,对应的两大组件就是就是index + store,所有的数据管理系统都包含这两部分。
邮件系统
思路,不像电梯那样有现实世界的对应,先use case 分析
系统边界:
1)外埠邮件收发:向外埠server投递,接受外部server的投递
2)邮件客户端收发:收信,发信
3)webMail
结构:
核心是一个目录和文件管理系统,加上不同的访问渠道。就是一个典型的基础API 外加上层应用的结构。