• 单例模式工厂模式

    2019-07-07 18:50:06
    单例模式 什么是单利设计模式? 保证一个类只有一个实例,并且提供一个访问该全局访问点。一个jvm中只能存在一个实例,保证对象唯一性。 单例模式应用场景 ​ servlet、struts2、springmvc、连接池、线程池、spring ...

    设计模式

    单例模式

    什么是单利设计模式?

    保证一个类只有一个实例,并且提供一个访问该全局访问点。一个jvm中只能存在一个实例,保证对象唯一性。

    单例模式应用场景

    ​ servlet、struts2、springmvc、连接池、线程池、spring

    单例优缺点:

    ​ 优点:节约内存、重复利用、方便管理

    ​ 缺点:线程安全问题

    单例创建方式(7种)

    ​ 饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高。

    /**
     * @program: JAVATest
     * @author: 王新春
     * @create: 2018-10-30 21:50
     * @description:   单例模式---饿汉式
     **/
    
    public class Singleton1 {
        //2.创建私有化唯一的对象,存在永久区,垃圾回收机制是不会回收
        private static final Singleton1 SINGLETON_1 = new Singleton1();
    
        //类初始化的时候,就会创建对象,天生线程安全,如果不使用对象时,会浪费内存
    
        //1.构造函数私有化
        private Singleton1() {
        }
        public static void main(String[] args) {
            Singleton1 singleton1 = Singleton1.getInstance();
            Singleton1 singleton2 = Singleton1.getInstance();
            System.out.println(singleton1 == singleton2);
        }
        /*
            为什么不会存在线程安全问题?
            对象唯一不会再被创建
         */
        //3.提供外部调用接口
        public static Singleton1 getInstance(){
            return SINGLETON_1;
        }
    }
    

    ​ 懒汉式:类初始化时,不会初始化该对象,真正需要使用时才会创建该对象,具备懒加载功能。

    /**
     * @program: JAVATest
     * @author: 王新春
     * @create: 2018-10-30 21:59
     * @description: 单例模式---懒汉式
     **/
    
    public class Singleton2 {
        //2.创建私有化唯一的对象
        private static Singleton2 singleton2;
        //类初始化时,不会创建该对象,真正需要时才会被加载(创建),天生线程不安全,,需要解决线程安全问题,所以效率低
    
        //1.构造函数私有化
        private Singleton2() {
        }
    
        public static void main(String[] args) {
            Singleton2 singleton2 = Singleton2.getInstance();
            Singleton2 singleton1 = Singleton2.getInstance();
            System.out.println(singleton1 == singleton2);
        }
    
        //3.提供外部调用接口
        /*
        线程安全问题
        多个线程时,存在创建多个对象的情况
        需要解决线程安全问题
         */
        public static synchronized Singleton2 getInstance() {
            if (singleton2 == null) {
                singleton2 = new Singleton2();
            }
            return singleton2;
        }
    }
    

    ​ 静态内部方式:结合了懒汉式和饿汉式的各自优点,真正需要对象的时候才会加载,加载类是线程安全的。

    ​ 枚举单例:使用枚举实现单例模式,优点:实现简单、调用效率高,枚举本身就是单例由jvm从根本上提供保障,避免通过反射和反序列化的漏洞,缺点:没有延迟加载功能。

    /**
     * @program: JAVATest
     * @author: 王新春
     * @create: 2018-10-30 22:09
     * @description:   单例模式---枚举方式
     **/
    
    public class Singleton3 {
    
        private Singleton3() {
        }
    
        public static Singleton3 getInstance(){
            return Singleton3Enum.INSTANCE.getInstance();
        }
        static enum Singleton3Enum{
            INSTANCE;
            private Singleton3 singleton3;
            private Singleton3Enum() {
                this.singleton3 = new Singleton3();
            }
            public Singleton3 getInstance(){
                return this.singleton3;
            }
        }
        public static void main(String[] args) {
            Singleton3 singleton3 = Singleton3.getInstance();
            Singleton3 singleton2 = Singleton3.getInstance();
            System.out.println(singleton3 == singleton2);
        }
    }
    

    ​ 双重检测锁方式(因为jvm本质重排序的原因,可能会初始化多次,不推荐使用)

    /**
     * @program: JAVATest
     * @author: 王新春
     * @create: 2018-10-30 22:36
     * @description:   单例模式---双重检验锁
     **/
    
    public class Singleton4 {
        //volatile   本身禁止重排序
        private static volatile Singleton4 singleton4;
    
        //1.构造函数私有化
        private Singleton4() {
        }
    
        public static void main(String[] args) {
            Singleton4 singleton2 = Singleton4.getInstance();
            Singleton4 singleton1 = Singleton4.getInstance();
            System.out.println(singleton1 == singleton2);
        }
    
        //3.提供外部调用接口
        /*
        线程安全问题
        多个线程时,存在创建多个对象的情况
        需要解决线程安全问题,使用双重检验锁,可以增加安全性,但是会降低效率
         */
        public static Singleton4 getInstance() {
    
            if (singleton4 == null) {
                synchronized (Singleton4.class){
                    if (singleton4 == null) {
                        singleton4 = new Singleton4();//存在重排序问题
                    }
                }
            }
            return singleton4;
        }
    }
    
    工厂模式

    什么时工厂模式?

    实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法、抽象工厂模式。

    简单工厂设计模式(不属于23种设计模式)

    简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

    优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化

    缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则

    举一个去4s点买汽车的例子

    汽车接口

    /**
     * @program: JAVATest
     * @author: 王新春
     * @create: 2018-10-31 22:30
     * @description:  总汽车类型
     **/
    
    public interface Car {
        void run();
    }
    

    汽车子类

    /**
     * @program: JAVATest
     * @author: 王新春
     * @create: 2018-10-31 22:31
     * @description: 比亚迪汽车
     **/
    
    public class Byd implements Car {
        @Override
        public void run() {
            System.out.println("比亚迪汽车在跑。。。。");
        }
    }
    
    /**
     * @program: JAVATest
     * @author: 王新春
     * @create: 2018-10-31 22:33
     * @description:   奔驰G500
     **/
    
    public class BCG500 implements Car {
        @Override
        public void run() {
            System.out.println("奔驰G500在跑。。。");
        }
    }
    

    工厂类

    /**
     * @program: JAVATest
     * @author: 王新春
     * @create: 2018-10-31 22:34
     * @description:    工厂模式-----简单工厂
     **/
    
    public class CarFactory {
        public static Car createCar(String name){
            if(name == null || name == ""){
                return null;
            }
            /*
                当类型过多时,不利于维护,也不利于扩展
             */
            switch (name){
                case "比亚迪":
                    return new Byd();
                case "奔驰G500":
                    return new BCG500();
                default:
                    return null;
            }
        }
    }
    

    测试类

    /**
     * @program: JAVATest
     * @author: 王新春
     * @create: 2018-10-31 22:45
     * @description:   测试类
     **/
    
    public class TestMain {
    
        public static void main(String[] args) {
            Car bcg500 = CarFactory.createCar("奔驰G500");
            bcg500.run();
        }
    }
    

    输出为:奔驰G500在跑。。。


    青春短暂,我在路上
    展开全文
  • 工厂模式和单例模式

    2019-09-01 16:47:29
    什么是工厂模式? 通过一个工厂类创建类似功能的不同实现类的父类或接口,不用关注你所获取的类是怎么实现的,只要通过工厂获取到对 象即可使用 工厂模式需要的三大模块: 一个父类或者一个接口:定义该功能的...

    什么是工厂模式?

          通过一个工厂类创建类似功能的不同实现类的父类或接口,不用关注你所获取的类是怎么实现的,只要通过工厂获取到对   象即可使用

    1. 工厂模式需要的三大模块:
      • 一个父类或者一个接口:定义该功能的方法、属性
      • 一个实现类或者子类:实现或者继承上面的接口或者父类
      • 工厂类:通过工厂类获取实现类的父类或者接口(多态)
    2. 优点:
      • 扩展性高:当你想增加一个产品,只需要扩展工厂类,并增加一个产品即可
      • 使用简单:屏蔽了产品的具体实现,使用者只用关注产品的接口即可
      • 高度解耦
    3. 缺点:

      • 每次增加一个产品的时候都需要新增一个实现类,这样下来类的数量不断增加,增加了系统 复杂度

    使用:在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

     

    /**
     *    接口
     */
    public interface Car {
    
        void run();
    }
    
    
    /**
     *  实现类
     */
    public class Bwm implements Car {
        @Override
        public void run() {
            System.out.println("宝马车在跑...");
        }
    }
    
    
    /**
     * 实现类
     */
    public class Benz implements Car {
        @Override
        public void run() {
            System.out.println("奔驰车在跑...");
        }
    }
    
    
    /**
     *  工厂方法模式
     */
    public interface CarFactory {
          Car createCar(String name);
    
    }
    
    
    /**
     * 奔驰汽车工厂
     */
    public class BenzFactory implements CarFactory {
    
        @Override
        public Car createCar(String name) {
            System.out.println("奔驰汽车...");
            return new Benz();
        }
    }
    
    
    /**
     * 宝马汽车工厂
     */
    public class BwmFactory implements CarFactory {
    
        @Override
        public Car createCar(String name) {
    
            System.out.println("宝马汽车...");
            return new Bwm();
        }
    }
    
    public class Client {
        public static void main(String[] args) {
    
            //工厂方法
            BwmFactory bwmFactory=new BwmFactory();
            Car car = bwmFactory.createCar("宝马");
            car.run();
    
            BenzFactory benzFactory=new BenziFactory();
            Car car1 = benzFactory.createCar("奔驰");
            car1.run();
        }
    }

    单例模式(Singleton Pattern)

         是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

    注意:

    • 1、单例类只能有一个实例。
    • 2、单例类必须自己创建自己的唯一实例。
    • 3、单例类必须给所有其他对象提供这一实例。
    //创建session单例对象
    public class SessionUtil {
    
        static SessionFactory sessionFactory;
    
        static{
            Configuration configuration=new Configuration().configure("hibernate.cfg.xml");
            sessionFactory=configuration.buildSessionFactory();
        }
    
        /**
         * 每次调用该方法是, 都获取到一个新的Session
         * @return
         */
        public static Session openSession(){
            return sessionFactory.openSession();
        }
        //获取和当前线程绑定的session(推荐使用)
        public static Session openCurrentSession(){
    
            return sessionFactory.getCurrentSession();
        }
       
    }
    

     实现方式:

       1、懒汉式, 没有加锁,线程不安全

            多线程不能正常工作。

    public class Singleton {  
        private static Singleton instance;  
        private Singleton (){}  
      
        public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
        }  
    }

            加锁synchronized  线程安全

               优点:第一次调用才初始化,避免内存浪费。
               缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。

    public class Singleton {  
        private static Singleton instance;  
        private Singleton (){}  
        public static synchronized Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
        }  
    }

    2、饿汉式

       优点:没有加锁,执行效率会提高。
       缺点:类加载时就初始化,浪费内存。

    public class Singleton {  
        private static Singleton instance = new Singleton();  
        private Singleton (){}  
        public static Singleton getInstance() {  
        return instance;  
        }  
    }

     

    展开全文
  • C#设计模式之单例模式

    前言

    早就想写几篇设计模式相关的博客了,马上要开始找工作了,借此机会复习一下设计模式同时也学习一下Markdown。本科阶段写过一个小游戏,当时能力有限,代码能力以及对设计模式的理解和运用都不够,后来研究生期间,由于《软件结构设计与模式分析》这门课的大作业需要我们编写并分析一个软件,软件类型不限,由于觉得这款小游戏题材不错,又有趣味性,所以借鉴了该游戏的思路并对它进行了重构,不仅界面进行了大量优化,同时也加入了一些设计模式,大大提高了软件的扩展性,这里结合这个小游戏,分析几个游戏中使用到的设计模式: 单例模式,策略模式和工厂方法模式。

    博客中没有对整个游戏的设计做详细的介绍,只是借这个游戏分析一下设计模式,游戏使用C#实现,游戏的VS工程和相关资料我上传到CSDN上了点击下载。大家可以结合代码看本文,这样能够更好的理解这个游戏和游戏中的几个设计模式。

    Github:https://github.com/qianqing13579/DragonQuest
    使用VS2013打开直接就可以运行



    游戏简介

    简介

    游戏是一个非常简单的RPG小游戏,游戏中主要有两类角色,分别为Hero-英雄和Enemy-敌人(怪兽),英雄是由玩家控制的角色,怪兽是系统控制的角色,其中怪兽分为不同等级,有小怪和大怪,游戏内容比较简单,就是双方发射子弹攻击对方,如果怪兽将英雄的生命值打为0,游戏结束,如果英雄将最后的大怪生命值打为0,游戏胜利。

    界面演示

    本来想做成GIF动画演示的,但是由于GIF文件比较大,上传不了,这里贴张图片,展示一下游戏的界面,大家可以下载源码运行,就可以看到整个游戏运行过程了。
    操作说明:"X"键发射子弹,方向键控制人物的移动

    游戏界面


    游戏整体结构

    打开VS工程,打开其中的类图文件ClassDiagram1.cd,就可以看到整个游戏的类图了
    VS工程

    游戏的类图如下
    这里写图片描述

    简单分析一下游戏的结构

    • Element:所有角色的根类
    • RoAndMi:继承自Element,是角色和子弹的基类
    • Roles及其子类:游戏中的所有角色
    • Missiles及其子类:游戏中所有角色的子弹
    • FireBehavior及其子类:游戏中所有角色的发射子弹的行为
    • HitCheck:游戏的主控类,用来控制游戏中所有元素
      游戏详细的实现过程,读者可以看源码,结合类图看源码,相信读者很快就能非常清楚整个游戏了

    下面的三个部分是游戏的核心

    • Roles及其子类:游戏中的所有角色
    • FireBehavior及其子类:游戏中所有角色的发射子弹的行为
    • HitCheck:游戏的主控类,用来控制游戏中所有元素

    分析游戏的时候,要把握好这三块。
    下面我们就结合这个小游戏,分析三种设计模式:单例模式,策略模式和工厂方法模式。


    单例模式

    定义

    确保一个类只有一个实例,并提供一个全局访问点。[1]P177(表示在参考文献[1]的177页,下同)

    经典的单例模式实现

    public class Singleton {
    	private static Singleton uniqueInstance;
     
    	// other useful instance variables here
     
    	private Singleton() {}
     
    	public static Singleton GetInstance() 
    	{
    		if (uniqueInstance == null) 
    		{
    			uniqueInstance = new Singleton();
    		}
    		return uniqueInstance;
    	}
     
    	// other useful methods here
    }
    

    总结一下单例的实现就是:一个私有,两个静态

    • 一个私有
      就是私有构造函数
      单例模式的思想就是一个类只有一个实例,即外部任何类都不能实例化该类,那么什么样的类外部不能实例化呢?我们知道,实例化一个类的时候,需要调用构造函数,而一般构造函数都是public的,所以能够被外部调用,所以能够在外部实例化,当将构造函数设置为private时,外部就不能调用类的构造函数了,也就不能实例化该类了,该类只能在类的内部实例化。这个思想是实现单例模式的关键。
    • 两个静态

    1.静态成员变量uniqueInstance,该成员变量就是类的唯一实例
    2.静态方法GetInstance(),用来获取该类的唯一实例

    前面提到了使用私有构造函数是实现单例模式的关键,那么下面的问题就是怎么在外部获取该单例呢?由于任何外部类都不能实例化该类,所以我们无法通过使用类的对象来调用类里面的方法获取单例(即不能通过Singleton singleton=new Singleton();singleton.GetInstance()来获取单例),只能通过类里面的静态方法,通过类名调用静态方法(Singleton.GetInstance())来获取单例,而静态方法只能调用静态成员,所以类的成员变量也必须是静态的。

    适用性

    当一个类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。[2]P84

    对有些类来说,只有一个实例很重要,如线程池,注册表,文件系统等
    虽然全局变量也可以提供全局访问点,但是不能防止你实例化多个对象

    游戏中的实现

    类图文件中双击HitCheck类,就能看到代码,当然也可以在工程中直接打开HitCheck.cs

    	/// <summary>
        /// 主控类,负责游戏中的各种角色的管理
        /// 1.AddElement()---添加元素
        /// 2.RemoveElement()----删除元素
        /// 3.Draw()----元素的绘制
        /// 4.DoHitCheck()---元素之间的碰撞检测
        /// 5.Restart()---重新开始游戏
        /// </summary>
        public class HitCheck
        {
            //游戏中的角色
            private Hero myHero = null;
            private List<MissileHero> missileHero = new List<MissileHero>();
            private List<Roles> enemy = new List<Roles>();
            private List<Missiles> enemyMissile = new List<Missiles>();
            private List<Element> bombs = new List<Element>();
            /// <summary>
            /// 构造函数私有化,禁止在其他地方实例化
            /// </summary>
            private HitCheck() { }
    
            private static  HitCheck instance;
    
            public static HitCheck GetInstance()
            {
                if (instance == null)
                {
                    instance = new HitCheck();
                }
                return instance;
            }
            ...
       }
    

    这个代码看上去是不是很熟悉,这就是个典型的单例模式的实现:一个私有,两个静态.

    为什么要使用单例模式

    刚开始写游戏的时候是没有用的,慢慢发现,游戏中的角色一旦过多,角色就很难管理,如角色的产生,角色的死亡,包括角色之间的碰撞检测。一旦游戏中要增加角色需要修改的代码很多,维护量比较大,所以就想设计一个类,实现对游戏中所有角色的管理,这样就可以很方便的对游戏中的角色进行管理。这个类主要控制游戏中的所有角色,包括对所有元素的增加,删除,以及碰撞检测(如英雄是否被敌人的子弹打中),这就要求该类只能有一个实例,不能有多个实例。不然游戏就会出错,所以设计为单例。读者分析一下HitCheck的源码就非常清楚其中使用单例的原因了。


    多线程问题

    经过上面的介绍和分析,读者对基本单例模式的实现和原理应该比较清楚了,那么是否这样的单例模式就非常好了呢?下面我们讨论一下在多线程中的问题。
    还是看上面经典单例模式的代码

    public class Singleton {
    	private static Singleton uniqueInstance;
     
    	// other useful instance variables here
     
    	private Singleton() {}
     
    	public static Singleton GetInstance() 
    	{
    		if (uniqueInstance == null) 
    		{
    			uniqueInstance = new Singleton();
    		}
    		return uniqueInstance;
    	}
     
    	// other useful methods here
    }
    

    假设现在有两个线程,以下是他们的执行步骤:
    多线程
    多线程中,由于每个线程执行的顺序不确定,就有可能产生2个实例。
    那怎么解决呢?这里提供以下两种方式,有更好的方式,欢迎大家提出来。

    方法1:”急切”实例化

    public class Singleton {
    	private static Singleton uniqueInstance = new Singleton();
     
    	private Singleton() {}
     
    	public static Singleton GetInstance() {
    		return uniqueInstance;
    	}
    }
    

    代码中,当类被加载时,静态变量uniqueInstance 会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建。多线程的时候,由于类加载的时候就创建了实例,所以不会出现多个实例的情况。

    方法2:“双重检查加锁”

    class Singleton 
    { 
        private static volatile Singleton instance = null; 
        //程序运行时创建一个静态只读的辅助对象
        private static readonly object syncObject= new object();
    
        private Singleton() { } 
    
        public static Singleton GetInstance() 
        { 
            //第一重判断,先判断实例是否存在,不存在再加锁处理
            if (instance == null) 
            {
                //临界区!
                //加锁的程序在某一时刻只允许一个线程访问
                lock(syncObject)
                {
                    //第二重判断
                    if(instance==null)
                    {
                        instance = new Singleton();  //创建单例实例
                    }
                }
            }
            return instance; 
        }
    }
    
    

    为了更好地对单例对象的创建进行控制,此处使用了一种被称之为双重检查加锁机制。在双重检查锁定中,当实例不存在且同时有两个线程调用GetInstance()方法时,它们都可以通过第一重instancenull判断,然后由于lock锁定机制,只有一个线程进入lock中执行创建代码,另一个线程处于排队等待状态,必须等待第一个线程执行完毕后才可以进入lock锁定的代码,如果此时不进行第二重instancenull判断,第二个线程并不知道实例已经创建,将继续创建新的实例,还是会产生多个单例对象,因此需要进行双重检查。

    volatile关键字
    volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。当成员变量发生变化时,强迫线程将变化值回写到共享内存(线程共享进程的内存)。这样,读取这个变量的值时候每次都是从momery里面读取而不是从cache读,这样做是为了保证读取该变量的信息都是最新的,而无论其他线程如何更新这个变量。
    此外,由于使用volatile关键字屏蔽掉了一些必要的代码优化,所以在效率上比较低,因此需要慎重使用。
    如果没有volatile关键字,第二个线程就可能没有及时读到最新的值,比如进程2在第二重判断的时候,进程1已经产生了一个实例,但是进程2没有读到最新的值,读到的instance还是为null,那么就会产生多个实例了,那么即使使用了双重检查加锁,也有可能产生多个实例。

    这两种方式在[1]P180~P182的处理多线程问题中也有非常清楚的阐述,用java描述,深入浅出,讲解地非常好。

    两种方式的比较

    ”急切”实例化在类被加载时就将自己实例化,它的优点在于无须考虑多个线程同时访问的问题,可以确保实例的唯一性;从调用速度和反应时间角度来讲,由于单例对象一开始就得以创建,因此要优于“双重检查加锁”。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来讲,”急切”实例化单例不及“双重检查加锁”单例,而且在系统加载时由于需要创建”急切”实例化单例对象,加载时间可能会比较长。

    “双重检查加锁”单例类在第一次使用时创建,无须一直占用系统资源,实现了延迟加载,但是必须处理好多个线程同时访问的问题。


    结束语

    游戏中还有两个模式:策略模式和工厂方法模式在下面的博客中讲述,读者可以先看看下载下来的资料中的PPT的相关内容,结合类图,可以先自行分析游戏源码中的这两个模式。第一次使用Markdown写博客,虽然不太熟练,但是觉得Markdown还是很强大的,写出的博客更美观。

    这里顺便推荐大家一本书:《Head First设计模式》,该本书获2005年第15届Jolt大奖,Jolt大奖是软件行业的"奥斯卡"奖。本书中的每个设计模式都结合具体实例,深入浅出,个人觉得比GOF设计模式更加通俗易懂。
          HeadFirst设计模式
    该书的所有代码我上传到CSDN上了,结合书中的代码看这本书会更好。
    点击下载


    参考文献

    [1] 《Head First设计模式(中文版)》 ,中国电力出版社
    [2] 《设计模式:可复用面向对象软件的基础》(著名的GOF设计模式),机械工业出版社


    非常感谢您的阅读,如果您觉得这篇文章对您有帮助,欢迎扫码进行赞赏。
    这里写图片描述

    展开全文
  • 一、单例模式优点 单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问; 意味着在内存中,只存在一个实例,减少了内存开销;   二、单例模式特点 只存在唯一一个...

    一、单例模式优点

    1. 单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问;
    2. 意味着在内存中,只存在一个实例,减少了内存开销;

     

    二、单例模式特点

    1. 只存在唯一一个实例;
    2. 提供统一对外访问接口,使得全局可对该单例的唯一实例进行访问;
    3. 自行实例化(私有构造函数,不允许外界对其进行实例化)。

     

    三、单例模式使用

    1. 资源管理器,资源对象数据的加载和卸载(无状态不需要实例化的对象);
    2. 单一客户端连接服务器等;
    3. 生命周期在游戏中永不消毁的对象。

     

    四、单例模式注意点

    1. 注意线程安全问题,在多线程、高并发的情况下,可能同时产生多个实例,违背了单例模式。
    2. Unity中如果过度使用单例模式,将会导致代码耦合度非常高,脚本与脚本之间的耦合,代码的后续拓展变得非常麻烦。一个过分依赖单例模式的开发者不能成为一个好的开发者,也不会去接触到更多优秀的设计模式。个人推荐ECS 实体 - 组件式编程。
    3. Unity中暂时不需要考虑多线程问题,Unity就只有一个主线程和开启多个辅助协程,不会出现多线程并发问题。
    4. 控制游戏对象的生成和销毁并不建议使用单例模式,可通过主游戏逻辑InGame进行事件下发,自行管理Update,使用工厂来进行对象的创建和销毁。

     

    五、单例模式常见模式

    1. 懒汉模式(最常用)

      1.1 提供私有构造函数;

      1.2 自行实例化;

      1.3 提供唯一实例,并且对外提供全局静态访问接口对该实例进行访问;

      • 代码如下:
        /// <summary>
        /// 普通模式
        /// </summary>
        public class Singleton
        {
            private static Singleton _instance = null;
        
            private Singleton()
            {
            }
        
            public static Singleton GetInstance()
            {
                if (_instance == null)
                {
                    _instance = new Singleton();
                }
                return _instance;
            }
        }

         

    2. 饿汉模式

      2.1 本类内部预先自行实例化出唯一实例;

      2.2 对外提供唯一访问接口(静态方法),对预先实例化的唯一实例进行访问;

      2.3 私有构造函数;

      • 代码如下:
           /// <summary>
          /// 饿汉单例模式
          /// </summary>
          public class Singleton
          {
              // 自行预先实例化,内部定义自己唯一实例,只供内部使用 //
              private readonly static  Singleton Instance = new Singleton();
      
              private Singleton() 
              {
                  // Do Something
              }
      
              // 提供外部访问的静态方法,来对内部唯一实例进行访问 //
              public static Singleton GetInstance()
              {
                  return Instance;
              }
          }

       

    3. 双重锁模式(解决线程安全问题)

      3.1 保证多线程中只存在唯一实例

      • 代码如下:
        /// <summary>
        /// 双重锁单例模式
        /// </summary>
        public class Singleton
        {
            private static Singleton _instance = null;
            private static readonly object _syslock = new object();  
            private Singleton()
            {
            }
        
            public static Singleton GetInstance()
            {
                // 最开始判断不存在的时候,该类从来未被实例化过 //
                if (_instance == null)
                {
                    // 锁定状态,继续搜索是否存在该类的实例 //
                    lock (_syslock)
                    {
                        // 如果不存在,在锁定状态下实例化出一个实例 //
                        if (_instance == null)
                        {
                            _instance = new Singleton();
                            return _instance;
                        }
                        else  // 锁定状态下,存在该类实例,直接返回 //
                        {
                            return _instance;
                        }
                    }
                }
                // 该实例本身就已经存在了,直接返回 //
                return _instance;
            }
        }

         

    4. 泛型单例模式

       

      4.1 在一个案例中,我们可能需要使用到不止一个单例模式类,甚至更多。那么此时,使用泛型单例模式模板来实现单例模式,我们可以有两种不同的方法来实现它:

      4.2首先我们来看下泛型模板,我们对泛型类进行约束,T只能是一个Class,并且有一个公共无参构造函数,代码如下:

      using System;
      using UnityEngine;
      
      public class SingletonProvider<T> where T : class ,new()
      {
          private SingletonProvider()
          {
          }
      
          private static T _instance;
          // 用于lock块的对象
          private static readonly object _synclock = new object();
      
          public static T Instance
          {
              get
              {
                  if (_instance == null)
                  {
                      lock (_synclock)
                      {
                          if (_instance == null)
                          {
                              // 若T class具有私有构造函数,那么则无法使用SingletonProvider<T>来实例化new T();
                              _instance = new T();
                              //测试用,如果T类型创建了实例,则输出它的类型名称
                              Debug.Log("{0}:创建了单例对象" + typeof(T).Name);
                          }
                      }
                  }
                  return _instance;
              }
              set { _instance = value; }
          }
      }
      • 4.2.1 然后我们定义了一个网络连接类 NetIO,使用单例提供类中的泛型T替代为具体的网络连接类进行使用:
      • 4.2.2 使用具体类替代泛型,用泛型单例提供类对该具体类达到提供唯一实例的单例实现效果:
      • 4.2.3 具体类中定义了字段NetIoCreateTime来存储该类实例化的时间,进行下一步分析该类实例是否是唯一实例,具体类代码如下:

        复制代码

        public class NetIO 
        {
        
            public static NetIO GetInstance()
            {
                return SingletonProvider<NetIO>.Instance;
            }
        
            public NetIO()
            {
                this.NetIoCreateTime = DateTime.Now;
            }
        
            public DateTime NetIoCreateTime
            {
                get { return _ct; }
                set { _ct = value; }
            }
        
            private DateTime _ct;
        }

        复制代码

      • 4.2.4 在Unity中Update参数中调用该类,对该类创建时间进行输出
        public void Update()
            {
                Debug.Log(NetIO.GetInstance().NetIoCreateTime);
            }
      • 4.2.5 测试结果如下:
      • image
      • 4.2.6 所有创建时间都一致,证明该类提供单例提供类中的泛型替代,达到了单例模式的效果,提供了该类的唯一实例访问

       

      4.3 在一个案例中,我们可能需要使用到不止一个单例模式类,甚至更多。那么此时,使用泛型单例模式模板来实现单例模式,我们可以有两种不同的方法来实现它:

      • 4.3.1 首先我们来看下泛型模板,我们对泛型类进行约束,T只能是一个Class,并且有一个公共无参构造函数,代码如下:
        using System;
        using UnityEngine;
        
        public class SingletonProvider<T> where T : class ,new()
        {
            private SingletonProvider()
            {
            }
        
            private static T _instance;
            // 用于lock块的对象
            private static readonly object _synclock = new object();
        
            public static T Instance
            {
                get
                {
                    if (_instance == null)
                    {
                        lock (_synclock)
                        {
                            if (_instance == null)
                            {
                                // 若T class具有私有构造函数,那么则无法使用SingletonProvider<T>来实例化new T();
                                _instance = new T();
                                //测试用,如果T类型创建了实例,则输出它的类型名称
                                Debug.Log("{0}:创建了单例对象" + typeof(T).Name);
                            }
                        }
                    }
                    return _instance;
                }
                set { _instance = value; }
            }
        }

         

      • 4.3.2 然后我们定义了一个网络连接类 NetIO,使用单例提供类中的泛型T替代为具体的网络连接类进行使用:
        1. 使用具体类替代泛型,用泛型单例提供类对该具体类达到提供唯一实例的单例实现效果:
        2. 具体类中定义了字段NetIoCreateTime来存储该类实例化的时间,进行下一步分析该类实例是否是唯一实例,具体类代码如下:
          public class NetIO 
          {
          
              public static NetIO GetInstance()
              {
                  return SingletonProvider<NetIO>.Instance;
              }
          
              public NetIO()
              {
                  this.NetIoCreateTime = DateTime.Now;
              }
          
              public DateTime NetIoCreateTime
              {
                  get { return _ct; }
                  set { _ct = value; }
              }
          
              private DateTime _ct;
          }

          复制代码

        3. 在Unity中Update参数中调用该类,对该类创建时间进行输出
          public void Update()
              {
                  Debug.Log(NetIO.GetInstance().NetIoCreateTime);
              }
        4. 测试结果如下:QQ截图20160114152652
        5. 所有创建时间都一致,证明该类提供单例提供类中的泛型替代,达到了单例模式的效果,提供了该类的唯一实例访问
    展开全文
  • 单例模式 什么是单例设计模式? 单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。...

    复习一下这两种设计模式

    单例模式

    什么是单例设计模式?

    单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
    具体实现
    先明白静态非静态的区别
    静态成员:静态成员变量是和类相关联的,可以作为类中"共"有的变量(是一个共性的表现),他不依赖特定对象的存在,访问的时候通过类名加点操作符加变量名来访问.https://www.jianshu.com/p/e1fee3558cb6
    需要:

    (1)将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。

    (2)在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型。

    (3)定义一个静态方法返回这个唯一对象。
    具体实现方式https://www.cnblogs.com/binaway/p/8889184.html

    简单工厂

    简单工厂模式基本实现流程
    具体产品类:将需要创建的各种不同产品对象的相关代码封装到具体产品类中
    抽象产品类:将具体产品类公共的代码进行抽象和提取后封装在一个抽象产品类中
    工厂类:提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入参数的不同创建不同的具体产品对象
    客户端:只需调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象

    abstract class Product
    {
    //所有产品类的公共业务方法
    public void MethodSame()
    {
    //公共方法的实现
    }

    //声明抽象业务方法
    public abstract void MethodDiff();
    }

    典型的具体产品类代码:
    class ConcreteProductA : Product
    {
    //实现业务方法
    public override void MethodDiff()
    {
    //业务方法的实现
    }
    }

    class Factory
    {
    //静态工厂方法
    public static Product GetProduct(string arg)
    {
    Product product = null;
    if (arg.Equals(“A”))
    {
    product = new ConcreteProductA();
    //初始化设置product
    }
    else if (arg.Equals(“B”))
    {
    product = new ConcreteProductB();
    //初始化设置product
    }
    return product;
    }
    }

    典型的客户端代码:
    class Program
    {
    static void Main(string[] args)
    {
    Product product;
    product = Factory.GetProduct(“A”); //通过工厂类创建产品对象
    product.MethodSame();
    product.MethodDiff();
    }
    }

    展开全文
  • 单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例 单例模式具有一定的伸缩性,类自己来控制实例化进程,类...
  • C# 单例模式和窗体的单例打开方法   第一种最简单,但没有考虑线程安全,在多线程时可能会出问题,不过俺从没看过出错的现象,表鄙视我…… public class Singleton{ private static Singleton _instance ...
  • 单例模式(Singleton Pattern)【使用频率:★★★★★】 1.概述: 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。 单例指的是只能存在一个...
  • 1:单例模式使用了简单工厂模式,换言之,单例类具有一个静态工厂方法,该方法返回一个实例,当然,一个抽象产品类同时是子类的工厂; 2:如下图(简单工厂模式架构图):抽象产品是生产具体水果的 3:单例...
  • 本质上,单例模式是一个只允许创建一个实例,并提供对这个实例简单的访问途径的类。一般而言,单例模式在创建实例时 不允许传递任何参数-否则不同参数导致不同的实例创建,就会出现问题!(如果同一个实例可以被同...
  • 单例模式 简单工厂模式 工厂方法和抽象工厂 代理模式 命令模式 策略模式 门面模式 桥接模式 观察者模式 接下来详细介绍灭一种设计模式(注意:下面的讲解都是基于java语言)1.单例模式 定义:Java中单例...
  • 单例模式就是保证系统中这个对象只有一个实例 什么是单例模式?  单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。   1、一个单例模式的要求有三点: 1)私有的变量 2)私有的...
  • unity->C#简单的单例模式 using UnityEngine; using System.Collections; public class c1 {  public static c1 aaa;  public int bbb;  private c1()  {  }  public static c1 instan
  • 单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此有些设计...
  • 单例模式 一、饿汉式: package single; public class EagerSingleton { private final static EagerSingleton EAGER_SINGLETON = new EagerSingleton(); private EagerSingleton() {} public static ...
  • 单例模式与延迟加载

    2018-07-17 13:04:08
    单例模式与延迟加载 首先,什么是单例模式(Singleton Pattern)?解释一下,单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类...
  • 单例模式工厂模式
1 2 3 4 5 ... 20
收藏数 4,476
精华内容 1,790