从王者荣耀看设计模式(二.单例模式)

从王者荣耀看设计模式(单例模式)

wz

一:简介

多个英雄可同时攻击敌方水晶,当水晶血条小于0,游戏结束

二:单例模式

一个类有且仅有一个实例,并且自行实例化向整个系统提供(水晶)。

模式动机
对于有些类来说,只有一个类的实例很重要。如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它提供一个访问该实例的办法。在本实例中,被各类英雄攻击的水晶是唯一的,为了保证该水晶只有一个实例,故使用单例模式

  • 这其中的设计原则有:
  1. 单例模式的类只提供私有的构造函数
  2. 类定义中含有一个该类的静态私有对象
  3. 该类提供了一个静态的共有的函数用于创建或获取它本身的静态私有对象
  • 单例模式的优点:
  1. 实例控制,单例模式会阻止其他对象实例化气自己的单例对象的副本,从而确保所有对象都访问唯一实例
  2. 灵活性,因为类控制了实例化过程,从而类可以灵活更改实例化过程
  • 单例模式的缺点
  1. 开销,虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销,可以通过静态初始化解决此问题。
  2. 可能的开发混淆,使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不可能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类

单例模式的三种实现
⑴. 懒汉式单例
优点:第一次调用才初始化,避免内存浪费
缺点:必须加synchronized才能保证单例,但加锁会影响效率

public class Singleton{
    private static Singleton singleton;
    private Singleton(){}  //此类不能被实例化
    public static synchronized Singleton getInstance(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}

⑵. 饿汉式单例
优点:没有加锁,执行效率会提高
缺点:类加载时就初始化,浪费内存

public class Singleton{
   private static final Singleton SINGLETON = new Singleton();
   private Singleton(){}//此类不能被实例化
   public static Singleton getInstance(){
        return SINGLETON;
    }
}

⑶.登记式单例
内部类只有在外部类被调用才加载,产生SINGLETON实例;又不用加锁。此模式有上述两个模式的优点,屏蔽了它们的缺点,是最好的单例模式

public class Singleton{
    private Singleton(){}//构造方法是私有的,从而避免外界利用构造方法直接创建任意多实例
    public static Singleton getInstance(){
        return Holder.SINGLETON;
    }
    private static class Holder{
        private static final Singleton SINGLETON = new Singleton();
    }
}

三:结构图

jg

四:代码实现

Base类(基地)

package com.game.domain;

/*
 * 基地(单例类)
 */

public class Base {
	// 构造方法私有
	private Base() {}
	//创建一个私有静态的基地对象的引用
	private static Base base=null;
	//提供一个公共的静态的创建基地对象或获取基地对象的方法
	public synchronized static Base getBase() {//同步
		if(base == null) {
			base = new Base();
		}
		return base;
	}
	
	//基地的生命值
	private int life = 999;
	//基地的摧毁状态
	private boolean destroy = false;
	
	public int getLife() {
		return life;
	}
	public void setLife(int life) {
		this.life = life;
	}
	public boolean isDestroy() {
		return destroy;
	}
	public void setDestroy(boolean destroy) {
		this.destroy = destroy;
	}
}

LuBanQiHao类,创建一个新英雄

package com.game.domain;

/*
 * 英雄(鲁班七号)
 */
public class LuBanQiHao extends Hero {
	
	public LuBanQiHao() {
		super.setHeroName("鲁班七号");
	}
	
	//英雄的自我介绍
	@Override
	public void display() {
		System.out.println("鲁班七号,智商二百五");
	}

	//英雄的普通攻击
	@Override
	public void normalAttack() {
		System.out.println("dadada~ 被动:集中火力");
	}

}

BaseTest测试类

package com.game.test;

import com.game.domain.Base;
import com.game.domain.Hero;
import com.game.domain.HouYi;
import com.game.domain.LuBanQiHao;

/*
 * 基地测试类B
 */
public class BaseTest {
	public static void main(String[] args) {
		System.out.println("所有英雄集合,攻击基地!");
		//模拟2个英雄,攻击基地
		new Thread(new Runnable() {
			public void run() {
				//1.创建英雄后羿,设置英雄单次攻击伤害值
				Hero hero = new HouYi();
				hero.setHeroHurt(100);//攻击力100B
				//2.获取基地,英雄攻击基地
				Base base = Base.getBase();
				destroyBase(hero,base);
			}
		}).start(); 
		
		new Thread(new Runnable() {
			public void run() {
				//1.创建英雄鲁班七号,设置英雄单次攻击伤害值
				Hero hero = new LuBanQiHao();
				hero.setHeroHurt(80);//攻击力B0
				//2.获取基地,英雄攻击基地
				Base base = Base.getBase();
				destroyBase(hero,base);
			}
		}).start();
	}
	
	//英雄摧毁基地的方法
	private static void destroyBase(Hero hero, Base base) {
		//1.显示那个英雄在攻击基地,英雄的伤害值是多少
		System.out.println("英雄:"+hero.getHeroName()+",伤害值:"+hero.getHeroHurt());
		//2.攻击基地
		//判断基地生命值>0,若生命值>0,英雄持续攻击B
		while(base.getLife() > 0) {
			synchronized(base){
				
				//2.1判断当前基地的状态是否已经被摧毁
				if(!base.isDestroy()) {
				//若没有被摧毁
				//攻击基地,基地剩余生命值减少
					//基地的剩余生命值=基地当前生命值-英雄的攻击力
					base.setLife(base.getLife()-hero.getHeroHurt());
					
					//模拟攻击基地的耗时操作
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
					//判断基地生命值>0,英雄攻击基地
					if(base.getLife()>0) {
						//判断基地生命值>0,英雄攻击基地
						System.out.println("英雄【"+hero.getHeroName()+"】正在攻击基地,基地剩余生命值:"+base.getLife());
					}else {
						//判断基地生命值<0,说明基地已被摧毁,更新基地的状态为摧毁,游戏胜利	
						base.setDestroy(true);
						System.out.println("基地已被【"+hero.getHeroName()+"】摧毁,游戏胜利!");
					}
				}
			}
		}
	}
}

五.运行结果

result

六.源代码下载

从王者荣耀看设计模式(单例模式)

原文地址:https://www.cnblogs.com/miaowulj/p/11417791.html