精华内容
下载资源
问答
  • JAVA设计模式之单例模式

    万次阅读 多人点赞 2014-04-16 06:51:34
     java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例、登记式单例。  单例模式有以下特点:  1、单例类只能有一个实例。  2、单例类必须自己创建自己的...

    本文继续介绍23种设计模式系列之单例模式。

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


    一、懒汉式单例

     

    //懒汉式单例类.在第一次调用的时候实例化自己 
    public class Singleton {
        private Singleton() {}
        private static Singleton single=null;
        //静态工厂方法 
        public static Singleton getInstance() {
             if (single == null) {  
                 single = new Singleton();
             }  
            return single;
        }
    }

     

    Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。

    (事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)

    但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全,如果你第一次接触单例模式,对线程安全不是很了解,可以先跳过下面这三小条,去看饿汉式单例,等看完后面再回头考虑线程安全的问题:

     

    1、在getInstance方法上加同步

     

    public static synchronized Singleton getInstance() {
             if (single == null) {  
                 single = new Singleton();
             }  
            return single;
    }

     

     

     

    2、双重检查锁定

     

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

     

    3、静态内部类

     

    public class Singleton {  
        private static class LazyHolder {  
           private static final Singleton INSTANCE = new Singleton();  
        }  
        private Singleton (){}  
        public static final Singleton getInstance() {  
           return LazyHolder.INSTANCE;  
        }  
    }  

    这种比上面1、2都好一些,既实现了线程安全,又避免了同步带来的性能影响。

     

     

     

     

     

     

    二、饿汉式单例

     

    //饿汉式单例类.在类初始化时,已经自行实例化 
    public class Singleton1 {
        private Singleton1() {}
        private static final Singleton1 single = new Singleton1();
        //静态工厂方法 
        public static Singleton1 getInstance() {
            return single;
        }
    }

    饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

     

     

     

     

    三、登记式单例(可忽略)

    //类似Spring里面的方法,将类名注册,下次从里面直接获取。
    public class Singleton3 {
        private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();
        static{
            Singleton3 single = new Singleton3();
            map.put(single.getClass().getName(), single);
        }
        //保护的默认构造子
        protected Singleton3(){}
        //静态工厂方法,返还此类惟一的实例
        public static Singleton3 getInstance(String name) {
            if(name == null) {
                name = Singleton3.class.getName();
                System.out.println("name == null"+"--->name="+name);
            }
            if(map.get(name) == null) {
                try {
                    map.put(name, (Singleton3) Class.forName(name).newInstance());
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
            return map.get(name);
        }
        //一个示意性的商业方法
        public String about() {    
            return "Hello, I am RegSingleton.";    
        }    
        public static void main(String[] args) {
            Singleton3 single3 = Singleton3.getInstance(null);
            System.out.println(single3.about());
        }
    }

     登记式单例实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。 

    这里我对登记式单例标记了可忽略,我的理解来说,首先它用的比较少,另外其实内部实现还是用的饿汉式单例,因为其中的static方法块,它的单例在类被装载的时候就被实例化了。

     

    饿汉式和懒汉式区别

    从名字上来说,饿汉和懒汉,

    饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了,

    而懒汉比较懒,只有当调用getInstance的时候,才回去初始化这个单例。

    另外从以下两点再区分以下这两种方式:

     

    1、线程安全:

    饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题,

    懒汉式本身是非线程安全的,为了实现线程安全有几种写法,分别是上面的1、2、3,这三种实现在资源加载和性能方面有些区别。


     

    2、资源加载和性能:

    饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,

    而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。

    至于1、2、3这三种实现又有些区别,

    第1种,在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的,

    第2种,在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗

    第3种,利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗,所以一般我倾向于使用这一种。

     

    什么是线程安全?

    如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

    或者说:一个类或者程序所提供的接口对于线程来说是原子操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题,那就是线程安全的。

     

    应用

    以下是一个单例类使用的例子,以懒汉式为例,这里为了保证线程安全,使用了双重检查锁定的方式:

     

    public class TestSingleton {
    	String name = null;
    
            private TestSingleton() {
    	}
    
    	private static volatile TestSingleton instance = null;
    
    	public static TestSingleton getInstance() {
               if (instance == null) {  
                 synchronized (TestSingleton.class) {  
                    if (instance == null) {  
                       instance = new TestSingleton(); 
                    }  
                 }  
               } 
               return instance;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public void printInfo() {
    		System.out.println("the name is " + name);
    	}
    
    }

    可以看到里面加了volatile关键字来声明单例对象,既然synchronized已经起到了多线程下原子性、有序性、可见性的作用,为什么还要加volatile呢,原因已经在下面评论中提到,

    还有疑问可参考http://www.iteye.com/topic/652440
    和http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

     

     

     

    public class TMain {
    	public static void main(String[] args){
    		TestStream ts1 = TestSingleton.getInstance();
    		ts1.setName("jason");
    		TestStream ts2 = TestSingleton.getInstance();
    		ts2.setName("0539");
    		
    		ts1.printInfo();
    		ts2.printInfo();
    		
    		if(ts1 == ts2){
    			System.out.println("创建的是同一个实例");
    		}else{
    			System.out.println("创建的不是同一个实例");
    		}
    	}
    }
    

     运行结果:

    结论:由结果可以得知单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。

    对于单例模式的几种实现方式,知道饿汉式和懒汉式的区别,线程安全,资源加载的时机,还有懒汉式为了实现线程安全的3种方式的细微差别。

    更多设计模式:23种设计模式系列

    作者:jason0539

    博客:http://blog.csdn.net/jason0539(转载请说明出处)

    展开全文
  • java构造模式

    千次阅读 2017-04-17 18:03:56
    一般在封装实体类时我们通常会用构造方法等形式往实体...那这个时候构造模式的出现完美的解决这一问题。 构造模式的出现很好的解决了多参数初始化的问题。我简单写个例子用来构造一个网络请求地址的实体类,带...

    一般在封装实体类时我们通常会用构造方法等形式往实体类传递参数,有可能对不同个数的参数进行初始化,你会定义出不同的构造方法,当然这都没问题,如果是当前实体类中的参数过于多时,这时候再用构造方法传递参数会有点力不从心,很大程度上会影响代码的可读性与美观性。那这个时候构造者模式的出现完美的解决这一问题。

    构造者模式的出现很好的解决了多参数初始化的问题。我简单写个例子用来构造一个网络请求地址的实体类,带大家简单了解下什么是构造者模式

     

    
    /**
     * Created by xiedong on 2017/4/17.
     */
    
    public class ParamsBuilder {
        private String url;
        private String password;
        private String username;
    
        public String getUrl() {
            return url;
        }
    
        public String getPassword() {
            return password;
        }
    
        public String getUsername() {
            return username;
        }
    
    
        public static class Builder {
            private String url = null;
            private String password = null;
            private String username = null;
    
            public Builder url(String url) {
                this.url = url;
                return this;
            }
    
            public Builder username(String username) {
                this.username = username;
                return this;
            }
    
            public Builder password(String password) {
                this.password = password;
                return this;
            }
    
            public ParamsBuilder builder() {
                return new ParamsBuilder(this);
            }
        }
    
    
        private ParamsBuilder(Builder b) {
            url = b.url;
            password = b.password;
            username = b.username;
        }
    
    
        @Override
        public String toString() {
            return "ParamsBuilder " + url + "/?username=" + username + "?password=" + password;
        }
    }
    


    初始化的时候

    ParamsBuilder params = new ParamsBuilder.Builder()
                    .url("wwww.baidu.com")
                    .username("xie")
                    .password("123")
                    .builder();

     

     

     

    展开全文
  • java_构造模式

    2017-02-08 19:34:58
    本人用java写的构造模式的小demo,源码里有详细的注释,保证一看就懂。欢迎交流指点。
  • java构造模式

    千次阅读 2019-05-19 01:18:02
    构造模式,又称之为建造者模式 应用场景 当一个bean类重载了多个构造方法时,并且参数随机使用时,考虑使用构造模式, 在springsercurity中设置拦截规则时,应用到了构造模式 Demo package com.yunsuibi;...

    介绍:

    	构造者模式,又称之为建造者模式,建造者模式,单例模式以及工厂模式都属于创建型模式
    

    应用场景

    当一个bean类重载了多个构造方法时,并且参数随机使用时,考虑使用构造者模式,
    

    Demo

    package com.yunsuibi;
    
    public class User {
    	private final String firstName; // required
    	private final String lastName; // required
    	private final int age; // optional
    	private final String phone; // optional
    	private final String address; // optional
    
    	private User(UserBuilder builder) {
    		this.firstName = builder.firstName;
    		this.lastName = builder.lastName;
    		this.age = builder.age;
    		this.phone = builder.phone;
    		this.address = builder.address;
    	}
    
    	public String getFirstName() {
    		return firstName;
    	}
    
    	public String getLastName() {
    		return lastName;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public String getPhone() {
    		return phone;
    	}
    
    	public String getAddress() {
    		return address;
    	}
    
    	@Override
    	public String toString() {
    		return "User [firstName=" + firstName + ", lastName=" + lastName + ", age=" + age + ", phone=" + phone
    				+ ", address=" + address + "]";
    	}
    
    	public static class UserBuilder {
    		private final String firstName;
    		private final String lastName;
    		private int age;
    		private String phone;
    		private String address;
    
    		public UserBuilder(String firstName, String lastName) {
    			this.firstName = firstName;
    			this.lastName = lastName;
    		}
    
    		public UserBuilder age(int age) {
    			this.age = age;
    			return this;
    		}
    
    		public UserBuilder phone(String phone) {
    			this.phone = phone;
    			return this;
    		}
    
    		public UserBuilder address(String address) {
    			this.address = address;
    			return this;
    		}
    
    		public User build() {
    			return new User(this);
    		}
    
    	}
    }
    

    运行

    public static void main(String[] args) {
    		User build = new User.UserBuilder("Jhon", "Doe").address("北京").build();
    		System.out.println(build);
    		User build2 = new User.UserBuilder("李四", "哈哈").address("12").build();
    		System.out.println(build2);
    	}
    

    个人博客 百度搜索:云随笔

    可以关注下博主的公众号,实时推送解决方案!
    公众号

    展开全文
  • 对象性质的构造: 有些情况下,一个对象会有一些重要的性质,在它们没有恰当的值之前,对象不能作为一个完整的产品使用。比如,一个电子邮件有发件人地址、收件人地址、主题、内容、附录等部分,而在最起码的收件人...

    建造模式是对象的创建模式。建造模式可以将一个产品的内部对象与产品的生产过程分割开啦,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
    对象性质的构造:
    有些情况下,一个对象会有一些重要的性质,在它们没有恰当的值之前,对象不能作为一个完整的产品使用。比如,一个电子邮件有发件人地址、收件人地址、主题、内容、附录等部分,而在最起码的收件人地址得到赋值之前,这个电子邮件不能发送。
    有些情况下,一个对象的一些性质必须按照某个顺序赋值才有意义。在某个性质没有赋值之前,另一个性质则无法赋值。这些情况使得性质本身的建造涉及到复杂的商业逻辑。这时候,此对象相当于一个有待建造的产品,而对象的这些性质相当于产品的零件,建造产品的过程是建造零件的过程。由于建造零件的过程很复杂,因此,这些零件的建造过程往往被“外部化”到另一个称做建造者的对象里,建造者对象返还给客户端的是一个全部零件都建造完毕的产品对象。
      建造模式利用一个导演者对象和具体建造者对象一个个地建造出所有的零件,从而建造出完整的产品对象。建造者模式将产品的结构和产品的零件的建造过程对客户端隐藏起来,把对建造过程进行指挥的责任和具体建造者零件的责任分割开来,达到责任划分和封装的目的。
      构造者模式的结构:
      这里写图片描述
    抽象建造者(Builder)角色:给 出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体建造者 (ConcreteBuilder)角色。具体建造者类必须实现这个接口所要求的两种方法:一种是建造方法(buildPart1和 buildPart2),另一种是返还结构方法(retrieveResult)。一般来说,产品所包含的零件数目与建造方法的数目相符。换言之,有多少 零件,就有多少相应的建造方法。
    具体建造者(ConcreteBuilder)角色:担任这个角色的是与应用程序紧密相关的一些类,它们在应用程序调用下创建产品的实例。这个角色要完成的任务包括:1.实现抽象建造者Builder所声明的接口,给出一步一步地完成创建产品实例的操作。2.在建造过程完成后,提供产品的实例。
    导演者(Director)角色:担任这个角色的类调用具体建造者角色以创建产品对象。应当指出的是,导演者角色并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者角色。
    产品(Product)角色:产品便是建造中的复杂对象。一般来说,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。
    导演者角色是与客户端打交道的角色。导演者将客户端创建产品的请求划分为对各个零件的建造请求,再将这些请求委派给具体建造者角色。具体建造者角色是做具体建造工作的,但是却不为客户端所知。
    一般来说,每有一个产品类,就有一个相应的具体建造者类。这些产品应当有一样数目的零件,而每有一个零件就相应地在所有的建造者角色里有一个建造方法。
    代码如下:

    public class ConcreteBuilder implements Builder{
    
        private Product product = new Product();
    
        /**
         * 产品零件构造方法1
         */
        public void builderPart1() {
            System.out.println("构建第一个零件");
            product.setPart1("id:123");
        }
    
        /**
         * 产品零件构造方法2
         */
        public void builderPart2() {
            System.out.println("构建第二个零件");
            product.setPart2("名称:变形金刚");
        }
    
        /**
         * 产品返还方法
         */
        public Product retrieveResult() {
            return product;
        }
    
    }
    public class Director {
    
        /**
         * 持有当前使用的构造器对象
         */
        private Builder builder;
    
        public Director(Builder builder) {
            super();
            this.builder = builder;
        }
    
        public void construct(){
            builder.builderPart1();
            builder.builderPart2();
        }
    }
    public static void main(String[] args) {
            Builder builder = new ConcreteBuilder();
            Director director = new Director(builder);
            director.construct();
    
            Product product = builder.retrieveResult();
            System.out.println(product.getPart1()+" "+product.getPart2());
    
        }
    展开全文
  • 主要介绍了Java抽象类的构造模板模式用法,结合实例形式分析了java使用抽象类构造模板模式相关操作技巧,需要的朋友可以参考下
  • Java设计模式构造者(Builder)模式

    千次阅读 2018-07-22 09:59:40
    Builder模式是为了弥补Java语言设计上的不足,话不多说,下面我们一起来看个栗子就知道啦! public class User{ String name; int age; String email; String address; public User(){ } //想要有名字...
  • 工厂方法模式Factory Method/虚拟构造模式Virtual Constructor/多态性工厂Polymorphic Factory为什么要有设计模式?为什么要有工厂方法模式?工厂方法模式的类图工厂方法模式的例子产品生产者消费者执行结果JDK中...
  • Java 构造方法私有化与单例模式

    千次阅读 2016-10-16 19:30:05
    上面的Singleton类里是存在构造方法的(如果一个类中没有明确的定义一个构造方法的话,会自动生成一个无参默认的构造方法),现在把构造方法修改一下: class Singleton { // 定义一个类 private ...
  • java 构造方法私有化及单态模式

    千次阅读 2015-04-20 17:21:29
    构造方法私有化及单态模式 构造方法封装 类的封装性不光体现在对属性的封装上,实际上方法也是可以被封装的,当然在方法封装中也包含了对构造方法的封装。例如:以下的代码,就是对构造方法进行了封装。...
  • Builder模式可以称为建造者模式,它将一个复杂对象的构建和表示分离,同样的构建过程可以创建不同的表示 适用场景: 相同的方法,不同执行顺序,产生不同事件结果 多个部件都可以装配到一个对象中,但产生的运行...
  • 重叠构造模式,javaBean模式,Builder模式的优缺点 模式 优点 缺点 重叠构造模式 形式简单 容易出错,参数表太长不容易控制,而且难以阅读 javaBean模式 构造过程被分割到好多个set中容易造成线程不安全...
  • import java.util.Objects; /** * @author 左金剛 * @Title: Builder * @Description: This is a common builder to create a bean, * the generic type must have a default construct, * otherwise will ...
  • Java刷ACM模式的各类输入输出构造

    千次阅读 多人点赞 2021-04-10 23:39:57
    Java刷ACM模式的各类输入输出构造 之前在LeetCode上刷题都是用到核心代码模式,后面面试发现部分笔试题使用的是ACM模式(第一次的时候因为构造输入输出问题,导致无法ac)所以含泪总结一下 1、多行输入 以牛客上的奖...
  • Java抽象类的作用——构造模板模式.pdf
  • JAVA设计模式初探之装饰者模式

    万次阅读 多人点赞 2014-04-01 09:07:37
    这个模式花费了挺长时间,开始有点难理解,其实就是 定义:动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。 设计初衷:通常可以使用继承来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 408,205
精华内容 163,282
关键字:

java构造模式

java 订阅