Java实现23种设计模式教程(1)

举报
摸鱼打酱油 发表于 2022/04/01 22:37:05 2022/04/01
【摘要】 个人简介作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。@[toc] Java设计模式 单例模式单例模式步骤:1.构造器私有2.创建对象(比如饿汉式就是先new,懒汉式就是判断为null再new)3.返回实例对象(都是一样) 饿汉式所谓的饿汉式,也就是提前new好对象,再提供一个方法,返回这个new...

个人简介

作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。

@[toc]

Java设计模式

单例模式

单例模式步骤:

1.构造器私有

2.创建对象(比如饿汉式就是先new,懒汉式就是判断为null再new)

3.返回实例对象(都是一样)

饿汉式

所谓的饿汉式,也就是提前new好对象,再提供一个方法,返回这个new好的对象实例。还有要把构造器私有化,通过方法new对象,控制到只有一个实例对象

饿汉式缺点:虽然是线程安全,但是会浪费资源,因为我们的饿汉式是一开始就new对象,如果没有人使用到这个对象,那就是一种资源的浪费,所以下面我们要讲懒汉式,懒汉式线程不安全,但是不会造成资源浪费,因为只有用到了才会new对象

代码实现:

1:实体类只需要正常写:

public class person {

    private String id;
    private String name;
    private int age;

    public person() {
    }

    public person(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

2:单例类:

public class hungry {

    /**
     * 单例模式-饿汉式
     */
    //1.创建static final对象
    private static final person person=new person();

    //2.构造器私有,为了让人只能用类去调用getInstance方法获取实例,而不能new这个单例的对象
    private hungry(){

    }


    //3.返回对象
    public static person getInstance(){
        return person;
    }


}

3.测试:

 public static void main(String[] args) {

         
        //测试单例
        person p1 = hungry.getInstance();
        person p2 = hungry.getInstance();

        //hashcode相同证明是同一个对象
        System.out.println("p1.hashCode:"+p1.hashCode());
        System.out.println("p2.hashCode:"+p2.hashCode());
        System.out.println("p1==p2:"+(p1==p2));

    }

4.结果:

p1.hashCode:1690716179
p2.hashCode:1690716179
p1==p2:true

饿汉式在JDK中的Runtime类运用

查看Runtime源码:

public class Runtime {
    private static final Runtime currentRuntime = new Runtime();

    private static Version version;

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class {@code Runtime} are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the {@code Runtime} object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}

这就是一种标准的单例模式-饿汉式

懒汉式(不加锁,不安全)

懒汉式是线程不安全的,但是他具有懒加载机制,也就是用到才new对象,这样不会造成资源的浪费

public class lazyNotSync {

    /**
     * 单例模式-懒汉式(不加锁) 线程不安全
     */
    //1.首先,单例模式要把构造器私有
    private lazyNotSync(){

    }

    //2.懒汉式的对象置为null
    private static person person=null;

    //3.返回实例
    public static person getInstance(){

        if(person==null){
            person=new person(); //这个new对象并赋值不是原子操作,所以在多线程是不安全的
            return person;
        }else {
            return person;
        }

    }



}

测试懒汉式不加锁的线程不安全性

class lazyNotSyncMain{

    public static void main(String[] args) throws InterruptedException {
        //这里不能用ArrayList,因为ArrayList是线程不安全的,所以在多线程的add,会导致少添加的情况
        CopyOnWriteArrayList<Object> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    list.add(lazyNotSync.getInstance());
                }
            }).start();
        }

        Thread.sleep(100);
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i).hashCode());
        }


    }
}

结果hashcode不一致,说明不是一个对象:

1929600551
1690716179
1053782781
1211888640
564160838

懒汉式(加锁,安全)

public class lazySync {

    /**
     * 单例模式-懒汉式,加锁,保证线程安全,但是呢,加了锁之后性能会下降
     *
     */

    //1.构造器私有
    private lazySync(){

    }

    //2.创建对象
    private static person person=null;
    private static final Object lock=new Object();

    //3.返回实例
    public static  person getInstance(){

        synchronized (lock){
            if(person==null){
                person=new person();
                return person;
            } else {
                return  person;
            }
        }

    }


}

测试安全性

class lazySyncMain{


    public static void main(String[] args) {
        
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                System.out.println(lazySync.getInstance().hashCode());
            }).start();
        }


    }


}

结果:

1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195

利用静态内部类

public class staticClass {

    /**
     * 利用静态内部类的特性来实现单例模式(推荐)
     * 优点:线程安全,懒加载(节省资源)
     * 可以说是饿汉式和懒汉式更好的一种
     * =====
     * 写法类似于饿汉式。。只是把new对象放到一个私有的静态内部类中
     *
     * =====
     * 静态内部类的特性:
     * 当classloader时静态内部类不会随着加载,当我们去调用时才会加载(懒加载)
     */

    //1.构造器私有
    private staticClass(){

    }

    //如果这段代码不放到静态内部类中,它将随着类加载而new对象(占资源)
//    private static final person person=new person();


    //2.创建对象(只不过是在静态内部类中创建对象)
    private static class personStatic{
        private static final person person=new person();
    }


    //3.返回对象

    public static person getInstance(){

        return personStatic.person;
    }





}

测试:

class staticClassMain{


    public static void main(String[] args) {

        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(staticClass.getInstance().hashCode());
                }
            }).start();

        }

    }
}

利用枚举(不太懂)

原型模式(多例)

原型模式其实就是复制的意思,包含着深拷贝和浅拷贝。浅拷贝复制的引用数据类型变量只是地址,深拷贝则是内容

实现原型模式的实体类要实现Cloneable接口

注意:实现了Cloneable的类才能拷贝(克隆)

浅拷贝

public class person implements Cloneable {

    private String id;
    private String name;
    private int age;
    private Firend firend; //朋友  ---模拟深拷贝和浅拷贝

    public person() {
    }

    public person(String id, String name, int age, Firend firend) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.firend = firend;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    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 Firend getFirend() {
        return firend;
    }

    public void setFirend(Firend firend) {
        this.firend = firend;
    }

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

    //浅拷贝
    @Override
    protected person clone() throws CloneNotSupportedException {
        person person = (person) super.clone(); //克隆对象
        return person;
    }



}
public class Firend {

    private String id;
    private String name;

    public Firend() {
    }

    public Firend(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

public class prototypeMain {


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

        person person = new person("001","张三",18,new Firend("999","小明同学"));

        person p1 = person.clone();

        System.out.println("person是否=p1:"+(person==p1)); //false ,说明克隆出来的对象不是同一个对象

        System.out.println("person:"+person);
        System.out.println("p1:"+p1);

        //说明我们的firend是浅拷贝
        System.out.println("person.getFirend().hashCode()==p1.getFirend().hashCode():"+(person.getFirend().hashCode()==p1.getFirend().hashCode()));


    }

结果:

person是否=p1:false
person:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
p1:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
person.getFirend().hashCode()==p1.getFirend().hashCode():true

深拷贝

深拷贝有多种方法,这里我们只使用一种,也是最简单的一种

person和Firend都要实现Cloneable和重写clone方法。。。。。。。。。。。。。才能实现深拷贝

public class person implements Cloneable {

    private String id;
    private String name;
    private int age;
    private Firend firend; //朋友  ---模拟深拷贝和浅拷贝

    public person() {
    }

    public person(String id, String name, int age, Firend firend) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.firend = firend;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    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 Firend getFirend() {
        return firend;
    }

    public void setFirend(Firend firend) {
        this.firend = firend;
    }

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

    //深拷贝
    @Override
    protected person clone() throws CloneNotSupportedException {
        person person = (person) super.clone(); //克隆对象

        //Firend也要实现Cloneable和clone方法
        //深拷贝:把引用数据类型变量单独的克隆并复制到person.firend
        person.firend=firend.clone();
        return person;
    }



}
public class Firend implements Cloneable {

    private String id;
    private String name;

    public Firend() {
    }

    public Firend(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected Firend clone() throws CloneNotSupportedException {
        Firend firend = (Firend) super.clone();
        return firend;
    }

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

public class prototypeMain {


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

        person person = new person("001","张三",18,new Firend("999","小明同学"));

        person p1 = person.clone();

        System.out.println("person是否=p1:"+(person==p1)); //false ,说明克隆出来的对象不是同一个对象

        System.out.println("person:"+person);
        System.out.println("p1:"+p1);

        //说明我们的firend是深拷贝
        System.out.println("person.getFirend().hashCode()==p1.getFirend().hashCode():"+(person.getFirend().hashCode()==p1.getFirend().hashCode()));


    }
}

结果:

person是否=p1:false
person:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
p1:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
person.getFirend().hashCode()==p1.getFirend().hashCode():false

工厂模式

工厂模式分为简单工厂和工厂方法,工厂模式和抽象工厂模式不是一个概念

总结:工厂模式只是生产同一类产品(比如手机工厂生产手机对象,电脑工厂生产电脑对象)

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。