门面模式、调停者模式、责任链模式

简介:

1、门面模式(facade)

门面模式:比如政府部门,你需要提交一些资料证明你自己是你自己,可能会从这个部门跑到那个部门,串来串去都办不好,但是如果有一个部门来统一协调这些部门之间的关系,而你只需要找到这个统一的部门来解决问题就可以了,效率就高了,这个就是所谓的门面模式。

2、调停者模式(Mediator)

调停者模式:上面所说的门面,其实也可以作为调停者,它对外来说是门面,而对内部的部门来说,他就是调停者,由它来协调部门之间的关系,各个部门只需要与这个调停部门联系,而相互之间不需要再有联系了,这就是所谓的调停者模式。

如下:我们举个例子,我写了一个坦克大战这个小游戏,游戏物体有坦克,子弹(暂时只有这两个),墙,碉堡等,我们每一个游戏物体都需要处理自己与其他游戏物体的关系,如:坦克与子弹相撞,坦克与墙相撞,坦克与坦克相撞,子弹与墙相撞,子弹与坦克相撞,子弹与碉堡相撞等等,每个物体都要与其他的物体联系,如果后续再加入其他的游戏物体,那么前面的每个物体都需要修改,能不能想个办法让他们不要有那么复杂的联系。

模式实例:

1、GameObject:游戏物体父类
package com.mashibing.tank;
import java.awt.*;
/**
 * 游戏物体的父类,无论是坦克,子弹,爆炸等等都继承自这个类
 */
public abstract class GameObject {
    public int x, y;
 public abstract void paint(Graphics g);
}
2、Tank:坦克类
package com.mashibing.tank;
import com.mashibing.strategy.FireStrategy;
import java.awt.*;
import java.util.Random;
public class Tank extends GameObject{
    public Dir dir = Dir.DOWN;
 private static final int SPEED = ProperMgr.getInt("tankSpeed");
 private boolean moving = true;
 public GameModel gm = null;
 public static int WIDTH = ResourceMgr.goodTankU.getWidth();
 public static int HEIGHT = ResourceMgr.goodTankU.getHeight();
 private boolean living = true;
 public FireStrategy fs;
 public Group group = Group.BAD;
 public Rectangle rect = new Rectangle();
 private Random random = new Random();
 public int oldX, oldY;
 public Tank(int x, int y, Dir dir, Group group, GameModel gm) {
        this.x = x;
 this.y = y;
 this.dir = dir;
 this.gm = gm;
 this.group = group;
 rect.x = this.x;
 rect.y = this.y;
 rect.width = WIDTH;
 rect.height = HEIGHT;
 try {
            if(group == Group.GOOD){
                String goodFsName = ProperMgr.get("goodFs").toString();
 fs =  (FireStrategy)Class.forName(goodFsName).getDeclaredConstructor().newInstance(); // 指定构造函数,进行对象的构造
 } else {
                String goodFsName = ProperMgr.get("badFs").toString();
 fs =  (FireStrategy)Class.forName(goodFsName).newInstance();//必须得有一个默认的空构造函数进行构造
 }
        } catch (Exception e) {
            e.printStackTrace();
 }
    }
    @Override
 public void paint(Graphics g) {
        if (!living) gm.remove(this);
 Color c = g.getColor();
 switch (dir) {
            case LEFT:
                g.drawImage(this.group == Group.GOOD ? ResourceMgr.goodTankL : ResourceMgr.badTankL,x,y,null);
 break; case UP:
                g.drawImage(this.group == Group.GOOD ? ResourceMgr.goodTankU : ResourceMgr.badTankU,x,y,null);
 break; case RIGHT:
                g.drawImage(this.group == Group.GOOD ? ResourceMgr.goodTankR : ResourceMgr.badTankR,x,y,null);
 break; case DOWN:
                g.drawImage(this.group == Group.GOOD ? ResourceMgr.goodTankD : ResourceMgr.badTankD,x,y,null);
 break; }
        move();
 }
    private void move() {
        oldX = x;
 oldY = y;
 if (!moving) return;
 switch (dir) {
            case LEFT:
                x -= SPEED;
 break; case UP:
                y -= SPEED;
 break; case RIGHT:
                x += SPEED;
 break; case DOWN:
                y += SPEED;
 break; }
        if(this.group == Group.BAD && random.nextInt(100)>95) {
            this.fire();
 }
        if (this.group == Group.BAD && random.nextInt(100)>95)
            randomDir();
 //边界检测
 boundsCheck();
 rect.x = this.x;
 rect.y = this.y;
 }
    private void boundsCheck() {
        if(this.x < 2) x = 0;
 if(this.y < 28) y = 30;
 if(this.x > TankFrame.GAME_WIDTH - Tank.WIDTH-2) x = TankFrame.GAME_WIDTH-Tank.WIDTH-2;
 if(this.y > TankFrame.GAME_HEIGHT - Tank.HEIGHT-2) y = TankFrame.GAME_HEIGHT-Tank.HEIGHT-2;
 }
    private void randomDir() {
        this.dir = Dir.values()[random.nextInt(4)];
 }
    public void fire() {
        fs.fire(this);
 }
    public void die() {
        this.living = false;
 }
    public void stop(){
        moving = false;
 }
    public void setDir(Dir dir) {
        this.dir = dir;
 }
    public static int getSPEED() {
        return SPEED;
 }
    public void setMoving(boolean moving) {
        this.moving = moving;
 }
    public void setGroup(Group group) {
        this.group = group;
 }
}
3、Bullet:子弹类
package com.mashibing.tank;
import java.awt.*;
public class Bullet extends GameObject{
    private static final int SPEED = ProperMgr.getInt("bulletSpeed");
 public Rectangle rect = new Rectangle();
 private Dir dir;
 public static int WIDTH = ResourceMgr.bulletD.getWidth();
 public static int HEIGHT = ResourceMgr.bulletD.getHeight();
 private boolean living = true; //子弹是否死掉,飞出窗口或者撞到敌人
 public GameModel gm = null;
 public Group group = Group.BAD;
 public Bullet(int x, int y, Dir dir, Group group, GameModel gm) {
        this.x = x;
 this.y = y;
 this.dir = dir;
 this.gm = gm;
 this.group = group;
 rect.x = this.x;
 rect.y = this.y;
 rect.width = WIDTH;
 rect.height = HEIGHT;
 gm.add(this);
 }
    @Override
 public void paint(Graphics g) {
        if(!living){
            gm.remove(this);
 }
        switch (dir) {
            case LEFT:
                g.drawImage(ResourceMgr.bulletL,x,y,null);
 break; case UP:
                g.drawImage(ResourceMgr.bulletU,x,y,null);
 break; case RIGHT:
                g.drawImage(ResourceMgr.bulletR,x,y,null);
 break; case DOWN:
                g.drawImage(ResourceMgr.bulletD,x,y,null);
 break; }
 move();
 }
    private void move() {
        switch (dir) {
            case LEFT:
                x -= SPEED;
 break; case UP:
                y -= SPEED;
 break; case RIGHT:
                x += SPEED;
 break; case DOWN:
                y += SPEED;
 break; }
        rect.x = this.x;
 rect.y = this.y;
 if (x < 0 || y < 0 || x > TankFrame.GAME_WIDTH || y > TankFrame.GAME_HEIGHT) living = false;
 }
    public void die() {
        this.living = false;
 }
}
4、Bullet:爆炸类
package com.mashibing.tank;
import java.awt.*;
public class Explode extends GameObject{
    public static int WIDTH = ResourceMgr.explodes[0].getWidth();
 public static int HEIGHT = ResourceMgr.explodes[0].getHeight();
 private GameModel gm = null;
 private int step = 0;
 public Explode(int x, int y,GameModel gm) {
        this.x = x;
 this.y = y;
 this.gm = gm;
 }
    @Override
 public void paint(Graphics g) {
       g.drawImage(ResourceMgr.explodes[step++],x,y,null);
 if(step >= ResourceMgr.explodes.length) {
           gm.remove(this);
 }
    }
}
5、GameModel:调停者/门面
package com.mashibing.tank;
import com.mashibing.cor.ColliderChain;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
 * 负责游戏物体之间的逻辑处理,也就是所谓的门面模式,
 * 它提供一系列接口供TankFrame调用,
 * 也是个调停者模式,它处理了游戏物体之间的碰撞,各种游戏物体的碰撞都通过本类
 * 中的碰撞检测去完成与其他物体的碰撞,而不是在游戏物体的类当中去处理具体的碰撞逻辑
 *
 * 也就是说以前呢子弹与坦克的碰撞逻辑在Bullet中去完成,假如以后加入了其他的游戏物体需要与子弹碰撞
 * 那么子弹类中的碰撞逻辑就需要修改,而现在在本类当中处理碰撞,只需提供相应的碰撞策略(Collider)就可以完成
 */
public class GameModel {
    //我方坦克
 public Tank myTank = new Tank(200,500, Dir.UP, Group.GOOD, this);
 //游戏物体:敌方坦克,子弹,爆炸
 private List objects = new ArrayList<>();
 //碰撞检测责任链
 ColliderChain chain = new ColliderChain();
 public GameModel(){
        //初始化敌方坦克
 int initTankCount = ProperMgr.getInt("initTankCount");
 for(int i = 0; i < initTankCount; i++) {
            add(new Tank(50+i*80, 200, Dir.DOWN, Group.BAD, this));
 }
    }
    public void add(GameObject go){
        this.objects.add(go);
 }
    public void remove(GameObject go){
        this.objects.remove(go);
 }
    public void paint(Graphics g) {
        Color c = g.getColor();
         g.setColor(Color.white);
         g.setColor(c);
         myTank.paint(g);
         for(int i = 0; i < objects.size(); i++) {
                    objects.get(i).paint(g);
         }
                //碰撞检测
         for(int i = 0; i < objects.size(); i++) {
            for(int j = i+1; j < objects.size(); j++){
                GameObject o1 = objects.get(i);
                 GameObject o2 = objects.get(j);
                 chain.collide(o1, o2);
 }
        }
    }
    public Tank getMyTank() {
        return myTank;
 }
}
6、Collider:碰撞处理接口
package com.mashibing.cor;
import com.mashibing.tank.GameObject;
public interface Collider {
    boolean collide(GameObject o1, GameObject o2);
}
7、BulletTankCollider:子弹与坦克的碰撞策略
package com.mashibing.cor;
import com.mashibing.tank.Bullet;
import com.mashibing.tank.Explode;
import com.mashibing.tank.GameObject;
import com.mashibing.tank.Tank;
public class BulletTankCollider implements Collider{
    @Override
 public boolean collide(GameObject o1, GameObject o2) {
        if(o1 instanceof Bullet && o2 instanceof Tank) {
            Bullet b = (Bullet) o1;
 Tank t = (Tank) o2;
 if(b.group == t.group) return false;
 if(b.rect.intersects(t.rect)) {
                t.die();
 b.die();
 int ex = t.x + Tank.WIDTH / 2 - Explode.WIDTH / 2;
 int ey = t.y + Tank.HEIGHT / 2 - Explode.HEIGHT / 2;
 b.gm.add(new Explode(ex, ey, b.gm));
 return false; }
        } else if(o1 instanceof Tank && o2 instanceof Bullet){
            return collide(o2, o1);
 }
        return true;
 }
}
8、TankTankCollider:坦克与坦克的碰撞策略
package com.mashibing.cor;
import com.mashibing.tank.GameObject;
import com.mashibing.tank.Tank;
public class TankTankCollider implements Collider{
    @Override
 public boolean collide(GameObject o1, GameObject o2) {
        if(o1 instanceof Tank && o2 instanceof Tank) {
            Tank t1 = (Tank) o1;
 Tank t2 = (Tank) o2;
 if(t1.rect.intersects(t2.rect)) {
                t1.x = t1.oldX;
 t1.y = t1.oldY;
 t2.x = t2.oldX;
 t2.y = t2.oldY;
 }
        }
        return true;
 }
}
9、ColliderChain:碰撞链:此处将碰撞的这些策略,连在一起(也就是装在一个集合当中),当一个物体检测自己与其他物体的碰撞时,将链条当中的碰撞策略都检测一遍即可(也就是循环一便)
package com.mashibing.cor;
import com.mashibing.tank.GameObject;
import java.util.LinkedList;
import java.util.List;
public class ColliderChain implements Collider{
    private List colliders = new LinkedList<>();
 public void add(Collider c){
        colliders.add(c);
 }
 
 //默认加入这两种碰撞策略,后续如有需要便往里面添加,也可以在配置文件里面配置碰撞策略,构造链条的时候读取配置文件然后加进colliders里面
    public ColliderChain(){
        add(new BulletTankCollider());
 add(new TankTankCollider());
 }
    public boolean collide(GameObject o1, GameObject o2) {
        for(int i = 0; i

结束:代码比较丑,后期重构之后再来改进

你可能感兴趣的:(java)