zoukankan      html  css  js  c++  java
  • 设计模式之装饰者decorator模式

    概念

    字面意思,用来做装饰的。

    原理:通过类的聚合

    例子(github游戏代码地址

    (游戏设计bug非常多,完全是为了学设计模式而写,勿喷。除了用的装饰模式,还混杂着其他设计模式,有些实在不适合混杂在一起,我又重新归零,另建了分支。

    操作:上下左右控制移动,ctrl键发射一颗子弹,A键发射4颗子弹)

    现有一个坦克的小游戏,我想要对坦克发射的子弹进行装饰。

    原先的游戏界面:

    我想要给子弹加个方框,然后再加个尾巴。效果图:

     

    游戏中类的结构图:

    稍作分析:

    所有游戏物体(Bullet,Tank,Wall)都抽象出共同父类GameObject。抽象的GODecorator装饰器又是从GameObject继承,并且聚合了GameObject。

    这样做的好处就是,我可以用修饰器对任意GameObject子类进行修饰,并且修饰之间可以扩展。

    GameObject抽象类

    package com.zl.pojo;
    
    import com.zl.enums.Group;
    
    import java.awt.*;
    
    /**
     * @Description
     * @Author zl
     * @Date 2020/9/14 16:04
     * @Version 1.0
     */
    public abstract class GameObject {
        public int x, y;
    
        public abstract void paint(Graphics g);
        public abstract int getWidth();
        public abstract int getHeight();
        public abstract Rectangle getRect();
        public abstract Group getGroup();
    
    }
    GameObject类

    Bullet类

    package com.zl.pojo;
    
    import com.zl.Audio;
    import com.zl.GameModel;
    import com.zl.ResourceImage;
    import com.zl.TankFrame;
    import com.zl.enums.Dir;
    import com.zl.enums.Group;
    
    import java.awt.*;
    import java.awt.image.BufferedImage;
    
    /**
     * @Description 子弹实体
     * @Author zl
     * @Date 2020/8/15 11:13
     * @Version 1.0
     */
    public class Bullet extends GameObject{
    
        //方向
        private Dir dir;
    
        //子弹宽高
        public static int width = ResourceImage.bulletD.getWidth();
        public static int heigth = ResourceImage.bulletD.getHeight();
    
        public Rectangle rect = new Rectangle();
    
        private final static int speed = 6;
    
        //子弹是否活着
        private boolean living = true;
    
        public Group group = null;
    
        TankFrame tf = null;
    
    
        public Bullet(int x, int y, Dir dir, Group group) {
            this.x = x;
            this.y = y;
            this.dir = dir;
            this.group = group;
            rect.x = this.x;
            rect.y = this.y;
            rect.width = width;
            rect.height = heigth;
            //GameModel.getInstance().add(this);
            if (group == Group.GOOD)
            new Thread(()->new Audio("com/zl/audio/tank_fire.wav").play()).start();
        }
    
        public Dir getDir() {
            return dir;
        }
    
        public void setDir(Dir dir) {
            this.dir = dir;
        }
    
    
        public void paint(Graphics g) {
    
            if (!living) {
                GameModel.getInstance().remove(this);
            }
    
    //        Color color = g.getColor();
    //        g.setColor(Color.RED);
    //        g.fillOval(x,y,10,10);
    //        g.setColor(color);
            move();
            BufferedImage image = null;
            switch (dir) {
                case UP:
                    image = ResourceImage.bulletU;
                    break;
                case DOWN:
                    image = ResourceImage.bulletD;
                    break;
                case LEFT:
                    image = ResourceImage.bulletL;
                    break;
                case RIGHT:
                    image = ResourceImage.bulletR;
                    break;
            }
            g.drawImage(image,x,y,null);
    
        }
    
        @Override
        public int getWidth() {
            return width;
        }
    
        @Override
        public int getHeight() {
            return heigth;
        }
    
        @Override
        public Rectangle getRect() {
            return rect;
        }
    
        @Override
        public Group getGroup() {
            return group;
        }
    
        private void move() {
            switch (dir){
                case UP:
                    y-=speed;
                    break;
                case DOWN:
                    y+=speed;
                    break;
                case LEFT:
                    x-=speed;
                    break;
                case RIGHT:
                    x+=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;
            GameModel.getInstance().collideWith();
        }
    
        /*public void collideWith(Tank tank) {
            if (this.group == tank.getGroup()) return;
            if (rect.intersects(tank.rect)) {
                tank.die();
                this.die();
                gm.gameObjects.add(new Explode(tank.getX()+ Tank.width/2- Explode.width/2, tank.getY()+ Tank.heigth/2- Explode.heigth/2, gm));
            }
        }*/
    
        public void die() {
            this.living = false;
        }
    }
    Bullet类

    GODecorator抽象类

    package com.zl.decorator;
    
    import com.zl.pojo.GameObject;
    
    import java.awt.*;
    
    public abstract class GODecorator extends GameObject {
    
        GameObject go;
    
        public GODecorator(GameObject go) {
            this.go = go;
        }
        @Override
        public void paint(Graphics g) {
            go.paint(g);
        }
    }
    GODecorator类

    RectDecorator类(为物体添加边框

    package com.zl.decorator;
    
    import com.zl.enums.Group;
    import com.zl.pojo.GameObject;
    
    import java.awt.*;
    
    public class RectDecorator extends GODecorator {
        public RectDecorator(GameObject go) {
            super(go);
        }
    
        @Override
        public void paint(Graphics g) {
            super.paint(g);
            Color color  = g.getColor();
            g.setColor(Color.BLACK);
            g.drawRect(super.go.x, super.go.y, getWidth()+2, getHeight()+2);
            g.setColor(color);
        }
    
        @Override
        public int getWidth() {
            return super.go.getWidth();
        }
    
        @Override
        public int getHeight() {
            return super.go.getHeight();
        }
    
        @Override
        public Rectangle getRect() {
            return super.go.getRect();
        }
    
        @Override
        public Group getGroup() {
            return super.go.getGroup();
        }
    }
    RectDecorator类

    TailDecorator类(为物体加上尾巴)

    package com.zl.decorator;
    
    import com.zl.enums.Group;
    import com.zl.pojo.GameObject;
    
    import java.awt.*;
    
    public class TailDecorator extends GODecorator {
        public TailDecorator(GameObject go) {
            super(go);
        }
    
        @Override
        public void paint(Graphics g) {
            this.x = super.go.x;
            this.y = super.go.y;
            super.paint(g);
            Color color  = g.getColor();
            g.setColor(Color.BLACK);
            g.drawLine(super.go.x, super.go.y, super.go.x-10, super.go.y-20);
            g.setColor(color);
        }
    
        @Override
        public int getWidth() {
            return super.go.getWidth();
        }
    
        @Override
        public int getHeight() {
            return super.go.getHeight();
        }
    
        @Override
        public Rectangle getRect() {
            return super.go.getRect();
        }
    
        @Override
        public Group getGroup() {
            return super.go.getGroup();
        }
    }
    TailDecorator类

    在没有修饰的情况下,当坦克开火打出一颗子弹时,直接new

    GameModel.getInstance().add(new Bullet(bx, by, t.getDir(), t.getGroup()));

    在需要为子弹加边框时,new一个bullet,把它传到rectDecorator里面即可

    GameModel.getInstance().add(
                    new RectDecorator(
                            new Bullet(bx, by, t.getDir(), t.getGroup())
                    )
            );

    如果需要在加边框的基础上加尾巴,接着把rectDecorator传到TailDecorator里面即可

    GameModel.getInstance().add(
                new RectDecorator(
                    new TailDecorator(
                        new Bullet(bx, by, t.getDir(), t.getGroup())
                    )
                )
            );

    如果需要修饰其他物体,以此类推

    心有所想,必有回响
  • 相关阅读:
    LeetCode 453 Minimum Moves to Equal Array Elements
    LeetCode 112 Path Sum
    LeetCode 437 Path Sum III
    LeetCode 263 Ugly Number
    Solutions and Summay for Linked List Naive and Easy Questions
    AWS–Sysops notes
    Linked List
    All About Linked List
    datatable fix error–Invalid JSON response
    [转]反编译c#的相关问题
  • 原文地址:https://www.cnblogs.com/zhulei2/p/13697733.html
Copyright © 2011-2022 走看看