在学习Observer观察者模式时发现它符合敏捷开发中的OCP开放-封闭原则, 本文通过一个场景从差的设计开始, 逐步向Observer模式迈进, 最后的代码能体现出OCP原则带来的好处, 最后分享Observer模式在自己的项目中的实现.
public class Observer {
public static void main(String[] args) {
Child c = new Child();
Dad d = new Dad(c);
new Thread(d).start();
new Thread(c).start();
}
}
class Child implements Runnable {
boolean wakenUp = false;//是否醒了的标志, 供父亲线程探测
public void wakeUp(){
wakenUp = true;//醒后设置标志为true
}
@Override
public void run() {
try {
Thread.sleep(3000);//睡3秒后醒来.
wakeUp();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public boolean isWakenUp() {
return wakenUp;
}
}
class Dad implements Runnable{
private Child c;
public Dad(Child c){
this.c = c;
}
public void feed(){
System.out.println("feed child");
}
@Override
public void run() {
while(true){
if(c.isWakenUp()){//每隔一秒看看孩子是否醒了
feed();//醒了就喂饭
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Observer {
public static void main(String[] args) {
Dad d = new Dad();
Child c = new Child(d);
new Thread(c).start();
}
}
class Child implements Runnable {
private Dad d;//持有父亲对象引用
public Child(Dad d){
this.d = d;
}
public void wakeUp(){
d.feed();//醒来通知父亲喂饭
}
@Override
public void run() {
try {
Thread.sleep(3000);//假设睡3秒后醒
wakeUp();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Dad{
public void feed(){
System.out.println("feed child");
}
}
feed(Child c)
方法时把自己作为参数传递给父亲, 父亲通过小孩对象就能获得小孩醒来时的具体信息.feed()
方法, 改成一个更加通用的actionToWakeUpEvent
, 对起床事件作出响应的方法.public class Observer {
public static void main(String[] args) {
Dad d = new Dad();
Child c = new Child(d);
new Thread(c).start();
}
}
class Child implements Runnable {
private Dad d;
public Child(Dad d){
this.d = d;
}
public void wakeUp(){//通过醒来事件让父亲作出响应
d.actionToWakeUpEvent(new WakeUpEvent(System.currentTimeMillis(), this));
}
@Override
public void run() {
try {
Thread.sleep(3000);
wakeUp();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Dad{
public void actionToWakeUpEvent(WakeUpEvent event){
System.out.println("feed child");
}
}
class WakeUpEvent{
private long time;//醒来的事件
private Child source;//发出醒来事件的源
public WakeUpEvent(long time, Child source){
this.time = time;
this.source = source;
}
}
public class Observer {
public static void main(String[] args) {
Child c = new Child();
c.addWakeUpListener(new Dad());
c.addWakeUpListener(new GrandFather());
c.addWakeUpListener(new Dog());
new Thread(c).start();
}
}
class Child implements Runnable {
private ArrayList<WakeUpListener> list = new ArrayList<>();
public void addWakeUpListener(WakeUpListener l){//对外提供注册监听的方法
list.add(l);
}
public void wakeUp(){
for(WakeUpListener l : list){//通知所有监听者
l.actionToWakeUpEvent(new WakeUpEvent(System.currentTimeMillis(), this));
}
}
@Override
public void run() {
try {
Thread.sleep(3000);
wakeUp();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
interface WakeUpListener{
public void actionToWakeUpEvent(WakeUpEvent event);
}
class Dad implements WakeUpListener{
@Override
public void actionToWakeUpEvent(WakeUpEvent event){
System.out.println("feed child");
}
}
class GrandFather implements WakeUpListener{
@Override
public void actionToWakeUpEvent(WakeUpEvent event) {
System.out.println("hug child");
}
}
class Dog implements WakeUpListener{
@Override
public void actionToWakeUpEvent(WakeUpEvent event) {
System.out.println("wang wang...");
}
}
class WakeUpEvent{
private long time;
private Child source;//事件源
public WakeUpEvent(long time, Child source){
this.time = time;
this.source = source;
}
}
false
, 然后设置坦克的生命也为false
, 最后产生一个爆炸并向服务器发送响应的消息. public boolean hitTank(Tank t) {//子弹击中坦克的方法
if(this.live && t.isLive() && this.good != t.isGood() && this.getRect().intersects(t.getRect())) {
this.live = false;//子弹死亡
t.setLive(false);//坦克死亡
tc.getExplodes().add(new Explode(x - 20, y - 20, tc));//产生一个爆炸
return true;
}
return false;
}
/**
* 坦克被击中事件监听者(由坦克实现)
*/
public interface TankHitListener {
public void actionToTankHitEvent(TankHitEvent tankHitEvent);
}
public class TankHitEvent {
private Missile source;
public TankHitEvent(Missile source){
this.source = source;
}
//省略 get() / set() 方法...
}
/* 坦克类 */
public class Tank implements TankHitListener {
//...
@Override
public void actionToTankHitEvent(TankHitEvent tankHitEvent) {
this.tc.getExplodes().add(new Explode(tankHitEvent.getSource().getX() - 20,
tankHitEvent.getSource().getY() - 20, this.tc));//坦克自身产生一个爆炸
if(this.blood == 20){//坦克每次扣20滴血, 如果只剩下20滴了, 那么就标记为死亡.
this.live = false;
TankDeadMsg msg = new TankDeadMsg(this.id);//向其他客户端转发坦克死亡的消息
this.tc.getNc().send(msg);
this.tc.getNc().sendClientDisconnectMsg();//和服务器断开连接
this.tc.gameOver();
return;
}
this.blood -= 20;//血量减少20并通知其他客户端本坦克血量减少20.
TankReduceBloodMsg msg = new TankReduceBloodMsg(this.id, tankHitEvent.getSource());//创建消息
this.tc.getNc().send(msg);//向服务器发送消息
}
//...
}
/* 子弹类 */
public class Missile {
//...
public boolean hitTank(Tank t) {//子弹击中坦克的方法
if(this.live && t.isLive() && this.good != t.isGood() && this.getRect().intersects(t.getRect())) {
this.live = false;//子弹死亡
t.actionToTankHitEvent(new TankHitEvent(this));//告知观察的坦克被打中了
return true;
}
return false;
}
//...
}
联系客服