1:单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例
1.1:饿汉式创建(静态 变量/代码块 方式)
package com.yrl.pattern;
/**
* 单例模式
*/
public class SingletonPattern {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance==instance2);
System.out.println("instance====="+instance.hashCode());
System.out.println("instance2===="+instance2.hashCode());
}
}
/**
* 静态变量创建
*/
class Singleton{
//1:构造器私有化,外部不能new
private Singleton(){ }
//2:类的内部创建对象
//方法一
// private final static Singleton instance = new Singleton();
//方法2
private static Singleton instance;
static {
instance = new Singleton();
}
//3:对外提供一个公有方法返回对象
public static Singleton getInstance(){
return instance;
}
}
说明:
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。
1.2:懒汉式(线程不安全)
/**
* 线程不安全
*/
class Singleton2{
private static Singleton2 instance;
private Singleton2 (){}
public static Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
说明:
1.3:懒汉式(线程安全)
/**
* 线程安全
*/
class Singleton2{
private static Singleton2 instance;
private Singleton2 (){}
public static synchronized Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
说明
该方式也实现了懒加载效果,同时又解决了线程安全问题。但是在getInstance()方法上添加了 synchronized关键字,导致该方法的执行效果特别低。从上面代码我们可以看出,其实就是在 初始化instance的时候才会出现线程安全问题,一旦初始化完成就不存在了。
1.4:懒汉式(双重检查)
/**
* 双重检查
*/
class Singleton2{
private static volatile Singleton2 instance;
private Singleton2 (){}
public static synchronized Singleton2 getInstance() {
if (instance == null) {
synchronized (Singleton2.class){
if(instance==null){
instance = new Singleton2();
}
}
}
return instance;
}
}
说明
1.5:懒汉式(静态内部类)
/**
* 静态内部类
*/
class Singleton2{
private Singleton2 (){}
private static class SingletonInstance{
private static final Singleton2 INSTANCE= new Singleton2();
}
public static Singleton2 getInstance(){
return SingletonInstance.INSTANCE;
}
}
说明
1)这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
2)静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getlnstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。
3)类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
4)优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
静态内部类单例模式是一种优秀的单例模式,是开源项目中比较常用的一种单例模式。在没有加任何锁的情况下,保证了多线程下的安全,并且没有任何性能影响和空间的浪费。
1.6:懒汉式(枚举)
package com.yrl.pattern;
/**
* 单例模式
*/
public class SingletonPattern {
public static void main(String[] args) {
Singleton instance = Singleton.INTERFACE;
Singleton instance2 = Singleton.INTERFACE;
System.out.println(instance==instance2);
instance.sayOK();
}
}
enum Singleton{
INTERFACE ;
public void sayOK(){
System.out.println("ok");
}
}
单例模式说明
l)单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
2)当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
3)单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)
2:工厂模式
3:原型模式
原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。
原型模式是一种对象创建型模式,它的工作原理非常简单:将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程。原型模式在软件开发中有较高的使用频率,很多软件提供的复制(Ctrl+C)和粘贴(Ctrl+V)就是原型模式的典型应用。
1.Prototype(抽象原型类):声明克隆方法的接口,是所有具体原型类的公共父类,它可以是抽象类也可以是接口,甚至还可以是具体实现类。
2.ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
3.Client(客户类):在客户类中,让一个原型对象通过克隆自身得到一个新的对象。
3.1:通用实现
通用的克隆实现方法是在具体原型类的克隆方法中实例化一个与自身类型相同的对象并将其返回,同时将相关的参数传入新创建的对象中,保证它们的成员变量相同。
public abstract class Prototype{
public abstract Prototype clone();
}
public class ConcretePrototype extends Prototype{
private String attr; //成员变量
public void setAttr(String attr){
this.attr=attr;
}
public String getAttr(){
return attr;
}
//克隆方法
public Prototype clone(){
Prototype prototype=new ConcretePrototype(); //创建新对象
prototype.setAttr(this.attr);
return prototype;
}
}
在客户类中只需要创建一个ConcretePrototype对象作为原型对象,然后调用其clone()方法即可得到对应的克隆对象。实例代码如下:
...
ConcretePrototype prototype=new ConcretePrototype();
prototype.setAttr("Sunny");
ConcretePrototype copy=(ConcretePrototype)prototype.clone();
...
此方法是原型模式的通用实现,它与编程语言本身的特性无关。
3.2:Java语言中的clone()方法和Cloneable接口(浅克隆)
在Java语言中,所有的Java类均继承自java.lang.Object类,Object类提供了一个clone()方法,可以将一个Java对象复制一份。在Java中可以直接使用Object提供的Clone()方法来实现对象的浅克隆。需要注意的是能够实现克隆的Java类必须实现一个标识接口Cloneable,表示这个Java类支持被复制。如果没有实现Cloneable接口但调用clone()方法,会抛出异常。
package com.atguigu.prototype.improve;
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
private String address = "蒙古羊";
public Sheep friend; //是对象, 克隆是会如何处理
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";
}
//克隆该实例,使用默认的clone方法来完成
@Override
protected Object clone() {
Sheep sheep = null;
try {
sheep = (Sheep)super.clone();
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
// TODO Auto-generated method stub
return sheep;
}
}
在客户端创建原型对象和克隆对象。
package com.atguigu.prototype.improve;
public class Client {
public static void main(String[] args) {
System.out.println("原型模式完成对象的创建");
// TODO Auto-generated method stub
Sheep sheep = new Sheep("tom", 1, "白色");
sheep.friend = new Sheep("jack", 2, "黑色");
Sheep sheep2 = (Sheep)sheep.clone(); //克隆
Sheep sheep3 = (Sheep)sheep.clone(); //克隆
Sheep sheep4 = (Sheep)sheep.clone(); //克隆
Sheep sheep5 = (Sheep)sheep.clone(); //克隆
System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode());
System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode());
System.out.println("sheep4 =" + sheep4 + "sheep4.friend=" + sheep4.friend.hashCode());
System.out.println("sheep5 =" + sheep5 + "sheep5.friend=" + sheep5.friend.hashCode());
}
}
注:1:对于成员变量是基本数据类型的成员变量,浅克隆可以直接复制一份给新对象
2:对于成员变量是引用类型的成员变量,比如某个对象,某个数组等,浅克隆会将该对象引用地址复制给新对象,实际上克隆对象的该成员变量就是原对象的该成员变量。在一个对象中修改,其余所有对象都会改变
3.3:深克隆
深克隆解决了上述问题,它有两种实现方式:(1):重写clone方法;(2):对象序列化
引用对象的类
package com.atguigu.prototype.deepclone;
import java.io.Serializable;
public class DeepCloneableTarget implements Serializable, Cloneable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
//构造器
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
//因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
重写clone方法具体原型类:即将引用对象单独克隆然后传给原型类对象
package com.atguigu.prototype.deepclone;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DeepProtoType implements Serializable, Cloneable{
public String name; //String 属性
public DeepCloneableTarget deepCloneableTarget;// 引用类型
public DeepProtoType() {
super();
}
//深拷贝 - 方式 1 使用clone 方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
//这里完成对基本数据类型(属性)和String的克隆
deep = super.clone();
//对引用类型的属性,进行单独处理
DeepProtoType deepProtoType = (DeepProtoType)deep;
deepProtoType.deepCloneableTarget = (DeepCloneableTarget)deepCloneableTarget.clone();
// TODO Auto-generated method stub
return deepProtoType;
}
}
对象序列化具体原型类:先将该对象用序列化方式的对象流输出,然后反序列化的方式读取改对象流转化为对象
//深拷贝 - 方式2 通过对象的序列化实现 (推荐)
public Object deepClone() {
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); //当前这个对象以对象流的方式输出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
DeepProtoType copyObj = (DeepProtoType)ois.readObject();
return copyObj;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
// TODO: handle exception
System.out.println(e2.getMessage());
}
}
}
客户类
package com.atguigu.prototype.deepclone;
public class Client {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
DeepProtoType p = new DeepProtoType();
p.name = "宋江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");
//方式1 完成深拷贝
// DeepProtoType p2 = (DeepProtoType) p.clone();
//
// System.out.println("p.name=" + p.name + "-----p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
// System.out.println("p2.name=" + p.name + "-----p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
//方式2 完成深拷贝
DeepProtoType p2 = (DeepProtoType) p.deepClone();
System.out.println("p.name=" + p.name + "-----p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
System.out.println("p2.name=" + p.name + "-----p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
}
}