Java学习之设计模式

写在前面:

        设计模式(设计模式)

                概述:编程中的一些套路,让我们的代码实现特定的目的,结构上更加优秀有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(早期使用归并排序)

                        规模小----------------->插入排序(稳定)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值