在學習Observer觀察者模式時發現它符合敏捷開發中的OCP開放-封閉原則, 本文經過一個場景從差的設計開始, 逐步向Observer模式邁進, 最後的代碼能體現出OCP原則帶來的好處, 最後分享Observer模式在本身的項目中的實現.html
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;
}
//...
}
複製代碼