设计模式

本文介绍了多种设计模式。单例模式有饿汉式和懒汉式,反射和反序列化可破坏单例;享元模式提倡重用对象;原型模式可克隆对象,有浅拷贝和深拷贝;建造器模式让对象创建更灵活;迭代器模式统一集合元素遍历。还介绍了策略模式,如排序算法中抽取比较器接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例模式

1.饿汉式模式,先创建好对象,等待调用
利用私有构造方法,只能创建一个实例对象

public class Singleton1 {

    /**
     * 让构造方法私有,别人就没法创建此类的实例了
     */
    private Singleton1() {

    }

    /**
     * 自己创建这个实例
     */
    private static final Singleton1 ME = new Singleton1();

    /**
     * 获取唯一实例
     * @return
     */
    public static Singleton1 getInstance() {
        return ME;
    }

}

2.懒汉模式,等到调用时再创建
(1)上述方法如果是多线程,就会破坏单例,所以用如下方法;

public class Singleton2 {

    private Singleton2() {

    }

    private static Singleton2 ME;


    // 线程1 ,    线程2
    /*
     线程1  锁住了 Singleton2.class 对象
            if (ME == null) {
     线程2  等待 线程1 释放 Singleton2.class 对象上的锁
     */

    public static synchronized Singleton2 getInstance() {
        // 当一次调用时ME == null为真, 当后续调用时ME == null为假,就不会执行创建对象的操作了
        if (ME == null) {
            ME = new Singleton2();
        }
        return ME;
    }
}

(2)懒汉式的最佳例子是利用私有静态内部类

public class Singleton4 {
    static{
        System.out.println("Singleton4类被加载了");
    }

    private Singleton4() {

    }

    // holder 拥有, 由静态内部类创建了他的唯一实例
    private static class Holder {
        static{
            System.out.println("Holder类被加载了");
        }
        static Singleton4 ME = new Singleton4();
    }

    public static Singleton4 getInstance() {
        return Holder.ME;
    }

    public static void test() {
        System.out.println("Singleton4其它方法");
    }
}

简化上面的

public class Singleton {
    //静态内部类,只有类才加载一次,由静态内部类创建唯一实例
    private Singleton(){}
    private static class Inner{
         static Singleton4 singleton=new Singleton();
    }
    public static Singleton getinterface(){
        return Inner.singleton;
    }

}

class Test3{
    public static void main(String[] args) {
        Singleton getinterface = Singleton.getinterface();
        System.out.println(getinterface);
    }
}

破坏单例的办法:

  1. 反射可以调用私有构造
  2. 反序列化可以破坏单例 (可以阻止)
    还原的时候不会再调用对象的构造方法

享元模式 flyweight

提倡重用已有的对象,而不是创建新的对象
Integer的享元范围 -128 ~ 127
Byte, Short, Charater, Long
连接池–对数据库连接对象进行了重用

public class TestFlyweight {
    public static void main(String[] args) {

        System.out.println(Integer.valueOf(1) == Integer.valueOf(1));    // true
        System.out.println(Integer.valueOf(100) == Integer.valueOf(100));// true
        System.out.println(Integer.valueOf(200) == Integer.valueOf(200));// false
    }
}
进入valueOf源码中看
public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
如果值在一定的范围内,则返回缓存中的这个值,超出范围才重新创建一个对象

原型模式 prototype

根据已有对象来创建新的对象, 克隆
使用场景,当对象属性很多,希望新的对象的大部分属性从原有对象复制而来
(1)浅拷贝

public class User implements Cloneable {

    private String name;
    private int age; // 18  --> 18
    private Date birthday; // #1234  --> #1234

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    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;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}



public class TestClone {

    public static void main(String[] args) throws CloneNotSupportedException {
        copy();

    }

    public static void copy() throws CloneNotSupportedException {
        User user = new User();
        user.setAge(18);
        user.setName("王小帅");
        user.setBirthday(new Date());

        User user2 = (User) user.clone();

        System.out.println(user == user2); // false
        System.out.println(user2.getAge());
        System.out.println(user2.getName());
        user2.getBirthday().setDate(28);
        System.out.println("新克隆用户的生日:"+user2.getBirthday());
        System.out.println("王小帅的生日:"+user.getBirthday());
    }
}
运行结果:
false
18
王小帅
新克隆用户的生日:Fri Jun 28 17:42:51 CST 2019
王小帅的生日:Fri Jun 28 17:42:51 CST 2019

在上述代码中, 克隆用户修改出生日期,从而导致了原用户 的出生 日期也被修改,原因是此为浅拷贝,在拷贝时引用数据类型拷贝的是地址,而地址相同指向同一块区域,由此引出深拷贝,深拷贝,利用序列化

public class User2 implements Cloneable, Serializable {

    private String name;
    private int age; // 18  --> 18
    private Date birthday; // #1234  --> #1234

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    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;
    }

    // ObjectOutputStream --> ByteArrayOutputStream --> byte[]

    @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;
    }
}
public class TestClone {

    public static void main(String[] args) throws CloneNotSupportedException {
        deepCopy();

    }

    public static void deepCopy () throws CloneNotSupportedException {
        User2 user = new User2();
        user.setAge(18);
        user.setName("王小帅");
        user.setBirthday(new Date());

        User2 user2 = (User2) user.clone();

        System.out.println(user == user2); // false
        System.out.println(user2.getAge());
        System.out.println(user2.getName());
       user2.getBirthday().setDate(28);
        System.out.println("新克隆用户的生日:"+user2.getBirthday());
        System.out.println("王小帅的生日:"+user.getBirthday());
    }

   
}

建造器模式

目的:让我们创建对象的过程更为灵活。适用于一步一步构建一个较为复杂的对象
jdk的体现:StringBuilder

public class Person {
    private String name;
    private String sex;
    private Integer weight;
    private Integer height;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", weight=" + weight +
                ", height=" + height +
                '}';
    }



    // 建造器
    public static class PersonBuilder{
        private String name;
        private String sex="男";
        private Integer weight=50;
        private Integer height;

        // 返回值类型不再是void 而是建造器类型本身
        public PersonBuilder name(String name) {
            this.name = name;
            return this;
        }
        public PersonBuilder sex(String sex) {
            this.sex = sex;
            return this;
        }
        public PersonBuilder weight(Integer weight) {
            this.weight = weight;
            return this;
        }
        public PersonBuilder height(Integer height) {
            this.height = height;
            return this;
        }
        public Person build() {
            // 需要的信息收集齐了
            //                builer
            return new Person(this.name,this.sex,this.weight,this.height);
        }
    }

    private Person(String name, String sex, Integer weight, Integer height) {
        this.name = name;
        this.sex = sex;
        this.weight = weight;
        this.height = height;
    }


    public String getName() {
        return name;
    }

    public String getSex() {
        return sex;
    }

    public Integer getWeight() {
        return weight;
    }

    public Integer getHeight() {
        return height;
    }
}

测试类
public class TestBuilder {
    // new Person.PersonBuilder() 0 170 "张三" "男"
    public static void main(String[] args) {
        Person person = new Person.PersonBuilder()
                .sex("女")
                //.name("张三")
                .height(170)
               .build();

        System.out.println(person);

        String str = new StringBuilder().append("aa").append(1).append(333.444).toString();
System.out.println(str);
    }
}

运行结果:
Person{name='null', sex='女', weight=50, height=170}
aa1333.444

迭代器模式(iterator)

定义:以一种一致的对集合内的元素进行遍历,而不用在乎集合内的数据结构

策略模式 (Strategy)

2.6 策略模式 (Strategy)

java 集合或数组的排序算法
Collections.sort
Arrays.sort
基本类型 双基点快速排序
对象类型 TimSort (早期使用归并排序)
规模小 插入排序

排序算法是固定的,排序的规则能否固定?–》 不能

把排序的规则抽取出来,形成比较器接口(Comparator),不同比较器的实现就称为策略

open close 开闭原则
算法不能改-- 体现的是close原则
比较器可以改 – 体现的是open原则

public class TestStrategy {

    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student("zhangsan", 18));
        list.add(new Student("lisi", 20));
        list.add(new Student("wangwu", 16));
        list.add(new Student("zhaoliu", 22));
        list.add(new Student("zhaoliu", 20));

        // 按年龄排
        Collections.sort(list,(a, b) ->  a.getAge() - b.getAge() );
        System.out.println(list);

        // 按名字排
        Collections.sort(list, (a, b) ->  a.getName().compareTo(b.getName()) );
        System.out.println(list);

        // 先按名字,再按年龄
        Collections.sort(list, (a, b) ->  {
            int x = a.getName().compareTo(b.getName());
            if(x != 0) {
                return x;
            } else {
                return a.getAge() - b.getAge();
            }
        } );
        System.out.println(list);
    }
}

class Student {
    private String name;
    private int age;

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Student(String name, int age) {

        this.name = name;
        this.age = age;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值