2019-08-09 Day10 单例设计模式以及扑克牌demo完善

目的

学习和了解单例设计模式,明白其作用和使用方法,完善Java知识基础学习;深入理解数组知识,学好Java基础知识中最重要的一部分;经过四天对Java基础的学习,已经对Java语言有一定了解,今天便做一个最基本的扑克牌demo,来将各类知识串联起来

单例设计模式

概念

java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种;单例模式有以下特点: 1、单例类只能有一个实例; 2、单例类必须自己自己创建自己的唯一实例;3、单例类必须给所有其他对象提供这一实例;
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例;在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例;这些应用都或多或少具有资源管理器的功能;每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中;每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用;总之,选择单例模式就是为了避免不一致状态,避免政出多头

关键词
1.整个程序都操作同一个对象
2.不允许用户创建这个类的一个对象,而将类的构造方法私有化
3.在自己的类里面提供创建对象的方法

两种形式

饿汉式

class Poker{
    //default sharedInstance manager
    //2.定义一个静态的成员变量  记录这个单例对象
    //饿汉式
    public static final Poker sharedInstance = new Poker();

    //1.默认构造函数
    private Poker(){

    }

    public void test(){

    }
}

懒汉式

class Player{
    public int count;

    //2.创建静态变量
    private static Player shared = null;

    //1.私有化构造方法
    private Player(){}

    //3.提供给外部一个访问的方法
    //懒汉式
    public static Player getInstance(){
        Object b = new Object();
        synchronized (b) {
            if (shared == null) {
                //如果没有创建 那么就创建一个
                shared = new Player();
            }
        }

        return shared;
    }
}

数组

Java数组里面保存的都是对象的引用(指针);改变数组里面对象的属性变量,原始对象的值也跟着改变,因为大家都是同一个内存空间

class Test2{
    public static void main(String[] args){
        //泛型
        ArrayList<Person> people = new ArrayList<>();

        //获取数组元素个数
        people.size();

        //添加数据
        Person xw = new Person();
        people.add(xw);

        Person zs = new Person();
        people.add(zs);

        //访问数据
        Person xw2 = people.get(0);
        xw2.name = "小王";

        System.out.println(xw2.name);
        System.out.println(xw.name);
    }
}

class Person{
    public String name;
}

情况演示

1.png

扑克牌游戏

设计游戏大致思路

2.png

封装输出语句

创建一个Untils类,专门封装输出语句

public class Utils {
    //如果不需要保存数据 没有成员变量
    //提供静态方法 访问方便
    public static void showText(boolean hasStar, boolean lineBreak, String... contents) {
        //判断是否需要显示分割线
        System.out.print(hasStar ? "*********************\n" : "");

        //判断输出的内容是多行还是一行
        if (contents.length == 1) {
            //有分隔线的时候需要换行
            System.out.print(contents[0] + (hasStar ? "\n" : ""));
        } else {
            //输出带编号的多行数据
            //1. 弃牌
            for (int i = 0; i < contents.length; i++) {
                System.out.println((i + 1) + ". " + contents[i]);
            }
        }

        System.out.print(hasStar ? "*********************\n" : "");

        //判断是否需要换行
        System.out.print(lineBreak ? "\n" : "");

    }
}

调用这个类创建欢迎界面

public class MyClass {
    public static void main(String[] args){
        //欢迎界面
        Utils.showText(true,true,new String[]{"欢迎使用扑克游戏"});
       }
}

创建Poker

创建Constant类,管理常量

下面代码为已完成状态

public class Constant {
    //用数组保存牌的点数
    public static final String[] dots = {"2","3","4","5","6","7","8","9","10","J","Q","K","A"};

    //保存固定的几个花色 黑红梅方
    public static final PokerType[] TYPES = {PokerType.SPADES,PokerType.HEARTS,PokerType.CLUBS,PokerType.DIAMONDS};

    //保存默认的玩家姓名
    public static final String[] DEFAULT_NAMES = {"刘德华","周润发","张家辉","周星驰"};

    //设置默认的金币
    public static final int MONEY = 1000;

    //底注
    public static final int BASE = 10;
}

定义PokerType类 管理牌的花色和id号

public class PokerType {
    public static final PokerType SPADES = new PokerType("♠",4);
    public static final PokerType HEARTS = new PokerType("♥",3);
    public static final PokerType CLUBS = new PokerType("♣",2);
    public static final PokerType DIAMONDS = new PokerType("♦",1);

    private String pic;
    private int id;

    public PokerType(){}

    //提供一个自定义的构造方法
    //默认的构造方法就被屏蔽了
    public PokerType(String pic, int id){
        this.pic = pic;
        this.id = id;
    }
    public String getPic() {
        return pic;
    }

    public void setPic(String pic) {
        this.pic = pic;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

}

创建PokerManager类 来管理牌的相关操作 比如发牌洗牌

import java.util.ArrayList;
import java.util.Collections;

/**
 * 管理牌的相关操作
 * 生成一副牌 洗牌 发牌 牌的比较
 */
public class PokerManager {
    //保存一副牌
    private ArrayList<Poker> pokers = new ArrayList<>();

    //创建静态对象
    public static final PokerManager manager = new PokerManager();

    //私有化过程方法
    private PokerManager(){}

    //定义一个方法 生成一副牌
    public void deal(){
        //遍历整个点数的数组
        for (int i = 0; i  < Constant.dots.length; i++){
            //获取相应的点数
            String dot = Constant.dots[i];

            //生成四种花色
            for (int j = 0; j < Constant.TYPES.length; j++){
                //创建一张牌
                Poker poker = new Poker(dot, Constant.TYPES[j]);
                //将这张牌保存起来
                pokers.add(poker);
            }
        }
        //洗牌
        Collections.shuffle(pokers);
    }
    public void show() {
        for (Poker poker : pokers) {
            System.out.print(poker.getDot() + poker.getType().getPic() + " ");
        }
        System.out.println();
    }

    /**
     * 给每个玩家发牌
     * @param players 所有参与玩家
     */
    public void dealCards(ArrayList<Player> players){
        for (int i = 0; i < players.size(); i++){
            Player player = players.get(i);

            //将数组里面对应的扑克给对应的玩家
            player.poker = pokers.get(i);
        }
    }

}

创建Player类 用于管理玩家信息

public class Player {
    public String name;
    public int id;
    public int money;
    public Poker poker;
    public boolean hasDiscard;//是否弃牌

    public Player(){}

    public Player(String name, int id, int money){
        this.name = name;
        this.id = id;
        this.money = money;
    }

    @Override
    //当打印一个对象的时候 就会默认去调用对象的toString方法
    //如果当前类里面没有实现这个方法 就到父类里面去找
    //object里面默认实现就是打印对象的首地址
    public String toString(){
        //1号玩家:刘德华 金币1000
        return id+"号玩家:"+name+" 金币"+money+" "+getPokerString();
    }

    public String getPokerString(){
        String pkString = "";
        if (poker != null){
            pkString = poker.getDot() + poker.getType().getPic();
        }
        return pkString;
    }

    /**
     * 下底注&下注
     * @param count 下注金额
     * @return -1:失败  >0: 成功
     */
    public int bet(int count){
        //判断自己的金币是否大于下注金额
        if (money >= count){
            money -= count;

            return count;
        }else{
            return -1;
        }
    }
    public void add(int count){
        money += count;
 }
}

创建PlayerManager类 管理玩家的相关操作

import java.util.ArrayList;

public class PlayManager {
    //记录当前下注的玩家编号
    public int currentPlayerIndex = 0;

    //保存所有的玩家
    public ArrayList<Player> players = new ArrayList<>();

    public static final PlayManager manager = new PlayManager();

    private PlayManager(){}

    //初始化玩家
    public void initPlayer(int count){
        for (int i = 0; i < count; i++){
            //创建玩家
            String name = Constant.DEFAULT_NAMES[i];
            Player player = new Player(name,i+1,Constant.MONEY);

            //保存玩家
            players.add(player);
        }
    }

    //输出玩家信息
    public void shows(){
        for (Player player:players){
            System.out.println(player);
        }
    }

    /**
     * 全场下底注
     * @param count 每局消耗的金币
     * @return -1:失败  >0: 成功
     */
    public int betAll(int count){
        for (Player player:players){
            int result = player.bet(count);
            if (result == -1){
                return -1;
            }
        }
        //返回总共下注的金币
        return count * players.size();
    }

    /**
     * 获取当前下注玩家
     * @return 玩家对象
     */
    public  Player currentPlayer(){
        return players.get(currentPlayerIndex);
    }

    /**
     * 当前剩余玩家数
     * @return
     */
    public int leftPlayerCount(){
        int total = 0;
        for (int i = 0; i < players.size(); i++){
            Player player = players.get(i);
            if (player.hasDiscard == true && player.money > 0){
                total++;
            }
        }
        return total;
    }

    /**
     * 查找下一个下注的人
     */
    public void changeNext(){
        int i = currentPlayerIndex;
        if (i == players.size()-1){
            i = 0;
        }else{
            i++;
        }
        //查找下一个可以参与的玩家
        for (; i < players.size(); i++){
            Player player = players.get(i);
            if (player.hasDiscard == true && player.money > 0){
                currentPlayerIndex = i;
                return;
            }
        }
    }

    /**
     * 奖励赢家
     */
    public void awardWinner(int total){
        Player winner ;
        int available = leftPlayerCount();
        if (available == 1){
            //只有一个玩家 即为赢家
            changeNext();
            winner = currentPlayer();
        }else{
            //需要比较这两个玩家的牌
            Player w1 = null;
            Player w2 = null;
            for (int i = 0; i < players.size(); i++){
                Player player = players.get(i);
                if (player.hasDiscard == false){
                    if (w1 == null){
                        w1 = player;
                    }else{
                        w2 = player;
                    }
                }
            }

            boolean result = w1.poker.bigerThen(w2.poker);
            if (result){
                winner = w1;
            }else {
                winner = w2;
            }
        }
        System.out.println(winner.id+"号玩家胜利 获取"+total+"金币");
        winner.add(total);
    }
}

创建GameCenter类 管理游戏进行的相关操作

public class GameCenter {
    //记录这局的筹码
    private int totalMoney;

    //开始游戏
    public void start(){
        System.out.println("游戏开始 请下底注");
        PlayManager manager = PlayManager.manager;
        //扣除底注
        manager.betAll(Constant.BASE);

        manager.shows();

        //发牌
        System.out.println("开始发牌");
        PokerManager.manager.dealCards(manager.players);

        manager.shows();

        int time = 0;//记录如果是两个人的次数
        boolean isFirst = true;
        int betMoney = 0;
        while (true){
            //获取当前玩家信息
            Player player = manager.currentPlayer();

            //提示选择操作
            System.out.println("请"+player.id+"号玩家选择操作;");

            Utils.showText(true,true,new String[]{"看牌","弃牌", isFirst?"下注":"跟注"});
            int choice = Utils.getInput();

            boolean flag = false;
            switch (choice){
                case 1:
                    //看牌
                    System.out.println(player.getPokerString());
                    flag =true;
                    break;
                case 2:
                    //弃牌
                    System.out.println(player.id+"号玩家弃牌");
                    player.hasDiscard = true;
                    break;
                default:
                    //下注
                    if (isFirst){
                        while (true) {
                            System.out.print("请输入下注金额:");
                            betMoney = Utils.getInput();

                            int result = player.bet(betMoney);
                            if (result == -1) {
                                //下注不成功
                                System.out.println("余额不足 ");
                            }else{
                                //下注成功
                                isFirst = false;
                                totalMoney += betMoney;
                                break;
                            }
                        }
                    }else{
                        //跟注
                        int result = player.bet(betMoney);
                        if (result == -1){
                            player.hasDiscard = true;
                        }else{
                            System.out.println("下注成功");
                            totalMoney += betMoney;
                        }
                    }
                    break;
            }

            if (flag == false){
                //计算当前还有多少人可以参与
                int available = manager.leftPlayerCount();

                if (available > 1){
                    //本剧结束
                    manager.changeNext();
                    Player winner = manager.currentPlayer();
                    System.out.println(player.id+"号玩家获得胜利 获得金币:"+totalMoney);
                    break;
                }

                if (available == 2){
                    time++;
                    if (time == 4){
                        //两个回合结束 结束游戏
                        break;
                    }
                }

                //切换到下一个人
                manager.changeNext();

            }
        }
    }

整体逻辑

public class MyClass {
    public static void main(String[] args){
        //欢迎界面
        Utils.showText(true,true,new String[]{"欢迎使用扑克游戏"});

        //生成一副牌
        PokerManager.manager.deal();
        //显示一副牌
        PokerManager.manager.show();

        //显示玩家人数
        Utils.showText(false,false,new String[]{"请输入玩家人数:"});
        int count = Utils.getInput();

        //初始化玩家
        PlayManager.manager.initPlayer(count);
        //显示玩家信息
        //PlayManager.manager.shows();

        //开始游戏
        GameCenter center = new GameCenter();
        center.start();
    }
}

心得体会

今天是正式地学习第一个完整的demo,其中还有很多不懂的,需要不断看视频和学习,才能将她摸透

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容