写在前面:
设计模式(设计模式)
概述:编程中的一些套路,让我们的代码实现特定的目的,结构上更加优秀有23种
【1】单例模式(singleton)的
(1)定义:虚拟机中这个类只有一个实例(对象)
方法1):饿汉式单例(一开始就创建好)
过程:A:让构造方法私有,别人就没法创造此类的实例了
B:自己创建这个实例
C:获取唯一实例
d:测试:不能在外部新的,只能调用方法获得
package Singleton;
public class Singleton {
private Singleton(){}//构造方法私有化
public static final Singleton ME = new Singleton();//自己创建这个唯一的实例
public static Singleton getInstance(){
return ME;
}//获取这个唯一的实例
}
public class Test {
public static void main(String[] args) {
Singleton singleton=Singleton.getInstance();//无论获取多少对象,都指的是同一的地址
Singleton singleton1=Singleton.getInstance();
Singleton singleton2=Singleton.getInstance();
System.out.println(singleton);
System.out.println(singleton1);
System.out.println(singleton2);
}
}
测试结果表明,无论创建多少的对象都指的是同一个。
方法2)懒汉式单例(用不到时不创建,用到时才创建)
(在多线程的情况下,为保证真正的单例,方法上加synchronized实现同步)
过程:A:构造方法私有
B:只声明对象
C:获取唯一实例
d:测试
public class SingletonDemo2 {
private SingletonDemo2(){}//私有化构造
private static SingletonDemo2 ME;//只声明对象
public static SingletonDemo2 getInstance(){
//获取唯一实例
if(ME==null){
ME=new SingletonDemo2();
//当第一次调用时,判断为真,当后续调用时判断为假,就不会创建新的对象了
}
return ME;
}
}
如果是在多线程的情况下给getInstance方法加锁同步
这样的话,线程1,锁住了SingletonDemo2.class对象,线程2就只能等待线程1释放锁对象
每次调用都要加锁,导致程序的性能比较低。更好的方式在下面...
方法3)枚举实现单例,(属于饿汉式)
public enum SingletonDemo3 {
ME;
public SingletonDemo3 me(){
System.out.println("I am ME");
return ME;
}
}
方法4)懒汉式的更佳实现
由静态内部类来创建唯一的实例
public class SingletonDemo4 {
static {
System.out.println("SingletonDemo4类被加载了");
//类加载是线程安全的,由JVM保证
}
//懒汉式的更佳实现
private SingletonDemo4(){ }//构造私有化
private static class Holder{
//静态内部类来创建它的唯一实例
static{
System.out.println("内部类Holder被加载了");
}
static SingletonDemo4 singletonDemo4=new SingletonDemo4();
//第一次类加载时进行初始化,以后不会类加载
}
public static SingletonDemo4 getInstance(){
return Holder.singletonDemo4;
}
}
追加5)破坏单例的方法
(1)反射:可以调用私有构造
(2)反序列化可以破坏单例(存到磁盘上,读一次生成一个对象)
【2】享元模式
思想:提供重用已有的对象,而非创建新的对象
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,减少对象数量从而改善应用所需的对象结构的方式。实现方式一般是通过HashMap完成。java常量池的设计初中也是为了减少内存占用,同时保证访问安全。
首先由一个例子引出:
public class Demo {
public static void main(String[] args) {
System.out.println(Integer.valueOf(10)==Integer.valueOf(10));
System.out.println(Integer.valueOf(100)==Integer.valueOf(100));
System.out.println(Integer.valueOf(200)==Integer.valueOf(200));
}
}
结果是:true
true
false
由此我们可以知道:Integer的享元范围是 -128~127(这里提一下±0)
除此之外,还有Byte,Short,Character,Long等
【3】原型模式(prototype)
思想:根据已有的对象来创建新的对象,克隆
使用场景:当对象属性很多,希望新的对象的大部分属性从原有对象复制而来
分类:深拷贝和浅拷贝
浅拷贝:(基本数据类型是没问题的)
package Prototype;
public class Prototype implements Cloneable{
private String name;
private int age;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
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 class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Prototype prototype = new Prototype();
prototype.setName("张三");
prototype.setAge(22);
//用在对象属性非常多时,希望新对象的大部分属性都从原有的对象复制过来
Prototype clone = (Prototype)prototype.clone();
System.out.println(prototype==clone);//克隆的是全新的对象,属性全都克隆过来
clone.setName("李四");
//clone.setAge(18);
System.out.println(prototype.getName()+"=="+prototype.getAge());
System.out.println(clone.getName()+"=="+clone.getAge());
}
}
但是除了基本数据类型
我们再加一个Date 数据类型时:
package Prototype;
import java.util.Date;
public class Prototype implements Cloneable{
private String name;
private int age;
private Date birth;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
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 Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
}
package Prototype;
import java.util.Date;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Prototype prototype = new Prototype();
prototype.setName("张三");
prototype.setAge(22);
prototype.setBirth(new Date());
//用在对象属性非常多时,希望新对象的大部分属性都从原有的对象复制过来
Prototype clone2 = (Prototype)prototype.clone();
System.out.println(prototype==clone2);//克隆的是全新的对象,属性全都克隆过来
clone2.setName("李四");
//clone.setAge(18);
clone2.getBirth().setDate(30);//
System.out.println("new Birth:"+clone2.getBirth());
System.out.println("old Birth:"+prototype.getBirth());
}
}
//我们发现他们两个的生日是相同的,很明显,他们只拷贝的是地址,而非复制了内容。
深拷贝:不止复制地址,所有的内容都要复制一份全新的,后面对象的修改不会影响之前的对象
序列化和反序列化(全新复制)
@Override
protected Object clone() throws CloneNotSupportedException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
// 把自己(当前对象)写入输出流
new ObjectOutputStream(os).writeObject(this);
// 拿到字节数组
byte[] bytes = os.toByteArray();
// 反序列化为新对象
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
// 对象输入流
ObjectInputStream ois = new ObjectInputStream(is);
return ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
【4】建造器模式(Builder)
目的:让我们创建对象的过程更为灵活,适用于一步一步构建一个较为复杂的对象
public class Test {
public static void main(String[] args) {
Builder builder
=new Builder.BuilderBuilder().name("张三").sex("男").height(178).weight(50).build();
System.out.println(builder.getName()+"=="+builder.getSex()+"=="+builder.getHeight()+"=="+builder.getWeight());
}
}
public class Builder {
private String name;
private String sex;
private Integer weight;
private Integer height;
public Builder(String name, String sex, Integer weight, Integer height) {
this.name = name;
this.sex = sex;
this.weight = weight;
this.height = height;
}
public static class BuilderBuilder{
private String name;
private String sex="女";
private Integer weight=50;
private Integer height;
//返回值类型不再是void 而是建造器类型本身
public BuilderBuilder name(String name){
this.name=name;
return this;
}
public BuilderBuilder sex(String sex) {
this.sex = sex;
return this;
}
public BuilderBuilder weight(Integer weight) {
this.weight = weight;
return this;
}
public BuilderBuilder height(Integer height) {
this.height = height;
return this;
}
public Builder build(){
return new Builder(this.name,this.sex,this.weight,this.height);
}
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public Integer getWeight() {
return weight;
}
public Integer getHeight() {
return height;
}
}
【5】迭代器模式
思想:以一种一致的方式对集合内的元素进行遍历,而不用在乎集合的数据结构
public class IteratorClass {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("张三",30));
list.add(new Person("李四",23));
list.add(new Person("张默",20));
list.add(new Person("王青",23));
list.add(new Person("赵宇",21));
list.add(new Person("周乐",19));
Collections.sort(list,(o1, o2) -> o1.getAge()-o2.getAge());
System.out.println(list);
Collections.sort(list,(o1, o2) -> o1.getName().compareTo(o2.getName()));
System.out.println(list);
Collections.sort(list,(o1, o2) -> {
int x=o1.getAge()-o2.getAge();
int num=x==0?x:o1.getName().compareTo(o2.getName());
return num;
});
System.out.println(list);
}
}
【6】策略模式(Strategy)
java集合或数组的排序算法:
基本类型----------------->双基点的快速排序(不稳定)
对象类型----------------->TimeSort(早期使用归并排序)
规模小----------------->插入排序(稳定)