首页 > 其他分享 >oop设计模式

oop设计模式

时间:2023-03-15 20:47:41浏览次数:36  
标签:Singleton return private class oop 单例 设计模式 public

设计模式

软件设计模式是一套反复使用,经验性的总结,具有一定普遍性,可以反复使用

1.软件设计原则

1.1开闭原则

对拓展开放,对修改关闭。在程序需要进行拓展时,不去修改原有的代码,实现一个热插拔的效果,简而言之,是为了使程序的拓展性好,易于维护和升级。

想要达到这样的效果,我们需要使用接口和抽象类。

因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。

1.2 里氏代换原则

里氏代换原则是面向对象设计的基本原则之一。

里氏代换原则:任何基类可以出现的地方,子类一定可以出现。通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能。换句话说,子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。

1.3 依赖倒转原则

高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

2.创建型模式

  • 单例模式

  • 工厂方法模式

  • 抽象工厂模式

  • 原型模式

  • 建造者模式

2.1 单例设计模式


单例模式是Java中最简单的设计模式之一,

2.1.1 单例模式的结构

  • 单例类。只能创建一个实例的类
  • 访问类。使用单例类

2.1.2 单例模式的实现

单例模式分两种:

​ 饿汉式:类加载就会导致该单实例对象被创建

​ 懒汉式:类加载不会导致该单实例对象被创建,首次使用该对象被创建

  1. 饿汉式

    方式一(静态变量方式)

    /**
     * @author ==> 许帅帅
     * 2022/12/16 16:25
     *单例模式 ==> 饿汉式:静态成员变量方式
     */
    public class Singleton {
        //创建私有构造方法
        private Singleton(){}
        //创建该类的对象,私有对象
        private static Singleton singleton = new Singleton();
    
        //设置一个暴露的方法,供外界使用这个单例对象
        public static Singleton getSingleton(){
            return singleton;
        }
    }
    

说明:

​ 该方式在成员位置声明Singleton类型的静态变量,并创建Singleton类的对象instance。instance对象是随着类的加载而创建的。如果该对象足够大的话,而一直没有使用就会造成内存的浪费。

​ 方式二-静态代码块方式

/**
 * @author ==> 许帅帅
 *单例模式的第二种方式,使用静态代码块进行创建对象
 */
public class Singleton {
    //私有构造方法,为了使用单例,不提供公开方法
    private Singleton(){}

    //创建私有对象
    private static Singleton singleton;
    //使用静态代码块为私有对象赋值
    static {
        singleton = new Singleton();
    }
    //将私有单例对象暴露出去,给外界使用
    public static Singleton getSingleton(){
        return singleton;
    }
}

说明:

​ 该方式在成员位置声明Singleton类型的静态变量,而对象的创建是在静态代码块中,也是对着类的加载而创建。所以和饿汉式的方式1基本上一样,当然该方式也存在内存浪费问题。

  1. 懒汉式

    方式一:线程锁方式

    说明:

    ​ 该方式也实现了懒加载效果,同时又解决了线程安全问题。但是在getInstance()方法上添加了synchronized关键字,导致该方法的执行效果特别低。从上面代码我们可以看出,其实就是在初始化instance的时候才会出现线程安全问题,一旦初始化完成就不存在了。

/**
 * @author ==> 许帅帅
 * 线程安全的懒汉式----单例实现
 * 在暴露为外界使用的方法上加上一把线程锁
 * 只有在A线程执行完毕之后,才会执行b线程
 *加上锁之后,会导致性能衰减
 */
public class Singleton_lazy {
    
    private Singleton_lazy(){}
    
    private static Singleton_lazy instance;
    
    private static synchronized Singleton_lazy getInstance(){
        //如果instance为空,就会创建一个,不为空,返回当前已经创建的对象,保证是单例的
        if (instance == null){
            instance = new Singleton_lazy();
        }
        return instance;
    }
}

​ 方式二(双重检查锁方式)

​ 再来讨论一下懒汉模式中加锁的问题,对于 getInstance() 方法来说,绝大部分的操作都是读操作, 读操作是线程安全的,所以我们没必让每个线程必须持有锁才能调用该方法,我们需要调整加锁的时 机。由此也产生了一种新的实现模式:双重检查锁模式

​ 双重检查锁模式是一种非常好的单例实现模式,解决了单例、性能、线程安全问题,上面的双重检测 锁模式看上去完美无缺,其实是存在问题,在多线程的情况下,可能会出现空指针问题,出现问题的 原因是JVM在实例化对象的时候会进行优化和指令重排序操作。

​ 要解决双重检查锁模式带来空指针异常的问题,只需要使用 volatile 关键字, volatile 关键字可以保 证可见性和有序性。

/**
 * @author ==> 许帅帅
 *懒汉式----双重检查锁方式
 */
public class Singleton_lazy {
    private Singleton_lazy() {}

    //volatile 关键字可以保证可见性和有序性
    private static volatile Singleton_lazy instance;

    public static Singleton_lazy getInstance() {
        //双重检查锁
        if (instance == null) {
            synchronized (Singleton_lazy.class) {
                if (instance == null) {
                    instance = new Singleton_lazy();
                }
            }
        }
        return instance;
    }
}

  1. 静态内部类方式

    /**
     * @author ==> 许帅帅
     * 单例模式----静态内部类方式
     */
    public class Singleton {
        private Singleton(){}
    
        //定义一个静态内部类,该类随着jvm只会加载一次
        private static class SingletonHolder{
            private static final Singleton singleton = new Singleton();
        }
        
        public static Singleton getInstance(){
            return SingletonHolder.singleton;
        }
    }
    

    说明:

    ​ 第一次加载Singleton类时不会去初始化INSTANCE,只有第一次调用getInstance,虚拟机加载SingletonHolder

    并初始化INSTANCE,这样不仅能确保线程安全,也能保证 Singleton 类的唯一性。

    小结:

    ​ 静态内部类单例模式是一种优秀的单例模式,是开源项目中比较常用的一种单例模式。在没有加任何锁的情况下,保证了多线程下的安全,并且没有任何性能影响和空间的浪费。

3.1 原型模式


3.1.1 原型模式

浅克隆:在进行拷贝时,拷贝对象引用地址

深克隆:拷贝对象,重新生成一个新的对象引用地址,不使用new,可以使用对象输入输出流

浅克隆

package com.xu.yuanxing.demo02;

/**
 * @author ==> 许帅帅
 * @version ==> 1.0
 * 2023/3/14 22:30
 */
public class Condition implements Cloneable {
    private String name;

    public String getName() {
        return name;
    }

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

    public void show() {
        System.out.println(name + "获得奖状!");
    }

    @Override
    public Condition clone() throws CloneNotSupportedException {
        return (Condition) super.clone();
    }
}
package com.xu.yuanxing.demo02;

/**
 * @author ==> 许帅帅
 * @version ==> 1.0
 * 2023/3/14 22:34
 */
public class Cline {
    public static void main(String[] args) throws CloneNotSupportedException {
        Condition condition = new Condition();

        condition.setName("张三");

        Condition clone = condition.clone();

        clone.setName("李四");
        clone.show();
    }
}

深克隆

package com.xu.yuanxing.demo03;

import java.io.Serializable;

/**
 * @author ==> 许帅帅
 * @version ==> 1.0
 * 2023/3/15 8:13
 */
public class Condition implements Cloneable , Serializable {
    private Student stu;

    public Student getStu() {
        return stu;
    }

    public void setStu(Student stu) {
        this.stu = stu;
    }
    public void show(){
        System.out.println(stu.getName()+"获得奖状!");
    }

    @Override
    public Condition clone() throws CloneNotSupportedException {
        return (Condition) super.clone();
    }
}
package com.xu.yuanxing.demo03;

import java.io.*;

/**
 * @author ==> 许帅帅
 * @version ==> 1.0
 * 2023/3/15 8:15
 */
public class Cline {
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        Condition condition = new Condition();
        Student student = new Student();
        student.setName("张三");
        condition.setStu(student);
//        Condition clone = condition.clone();

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\txt01.txt"));
        objectOutputStream.writeObject(condition);

        objectOutputStream.close();

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\txt01.txt"));
        Student student1 =(Student) objectInputStream.readObject();
        condition.setStu(student1);
        Student stu = condition.getStu();
        System.out.println(stu == student);
        condition.show();
    }
}

2.3 创建者模式


  1. 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于: 某个对象的构建过程复杂的情况
  2. 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象,相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
  3. 建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须道其内部的具体构造细节。

类图

package com.xu.constructor;

/**
 * @author ==> 许帅帅
 * @version ==> 1.0
 * 2023/3/15 19:16
 */
public abstract class Builder {

    protected Bike bike = new Bike();


    public abstract void createFrame();

    public abstract void createName();

    public abstract Bike createBike();

}
package com.xu.constructor;

/**
 * @author ==> 许帅帅
 * @version ==> 1.0
 * 2023/3/15 19:20
 */
public class OFOBuilder extends Builder{


    @Override
    public void createFrame() {
        bike.setFrame("钛合金车架");
    }

    @Override
    public void createName() {
        bike.setName("OFO");
    }

    @Override
    public Bike createBike() {
        return bike;
    }
}
package com.xu.constructor;

/**
 * @author ==> 许帅帅
 * @version ==> 1.0
 * 2023/3/15 19:24
 */
public class Director {

    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    //组装组件
    public Bike construct() {
        builder.createName();
        builder.createFrame();
        return builder.createBike();
    }
}

使用场景

  • 建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所通常在以下场合使用。
  • 创建的对象较复杂,由匆个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
    创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。

创建者模式升级

使用链式调用,创建对象,给产品一个私有构造方法

package com.xu.constructor.demo02;

/**
 * @author ==> 许帅帅
 * @version ==> 1.0
 * 2023/3/15 19:53
 */
public class Phone {
    private String cpu;
    private String screen;

    private String camera;

    private Phone(Builder builder){
        this.cpu = builder.cpu;
        this.camera = builder.camera;
        this.screen = builder.screen;
    }

    @Override
    public String toString() {
        return "Phone{" +
                "cpu='" + cpu + '\'' +
                ", screen='" + screen + '\'' +
                ", camera='" + camera + '\'' +
                '}';
    }

    public final static class Builder {
        private String cpu;
        private String screen;
        private String camera;


        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public Builder screen(String screen) {
            this.screen = screen;
            return this;
        }

        public Builder camera(String camera) {
            this.camera = camera;
            return this;
        }
		//创建phone对象
        public Phone build(){
            return new Phone(this);
        }

    }
}

标签:Singleton,return,private,class,oop,单例,设计模式,public
From: https://www.cnblogs.com/xushuaishuai/p/17219908.html

相关文章

  • Hadoop/spark安装实战(系列篇5) scala安装
     Hadoop/spark安装实战(系列篇5)scala安装1/scala解压缩 [root@localhostsetup_tools]#tar -zxvf   scala-2.10.4.tgz2将文件移到/usr/local  mv scala-2......
  • Hadoop/spark安装实战(系列篇1)准备安装包
    下载各安装包,准备安装CentOS使用网盘上下载的vmvare虚拟机centos系统spark1.0.0​​​http://d3kbcqa49mib13.cloudfront.net/spark-1.0.0-bin-hadoop1.tgz​​scala​......
  • 深入nodejs的event-loop
    此处如无特殊指出的话,eventloop的语境都是指nodejs本文研究所用的nodejs环境是:操作系统window10+nodejs版本号为v12.16.2什么是eventloop?eventloop是指由libuv......
  • 【大数据】Centos7、Hadoop3.3.1、分布式搭建
    主要遵照 https://www.cnblogs.com/lehoso/p/15550119.html进行搭建,文章里写的很清楚了,我就不多说了。在搭建过程中,用思维导图绘制了一个大纲。可点击下载安装过程中的......
  • 设计模式(二十一)----行为型模式之状态模式
    1概述【例】通过按钮来控制一个电梯的状态,一个电梯有开门状态,关门状态,停止状态,运行状态。每一种状态改变,都有可能要根据其他状态来更新处理。例如,如果电梯门现在处于运行......
  • 前端设计模式——代理模式
    代理模式(ProxyPattern):前端设计模式中的代理模式是一种结构型模式,它允许在不改变原始对象的情况下,通过引入一个代理对象来控制对原始对象的访问。代理对象充当原始对象的中......
  • Day04-设计模式之原型模式
    引例在介绍原型模式前,我们先从实际问题出发,对比解决方法前后优劣点。问题:现在有一只羊(包含属性:名字Dolly、年龄2),需要克隆10只属性完全相同的羊。1、一般解法1、定义Sh......
  • Day05-设计模式之适配器模式
    设计模式之适配器模式适配器模式介绍适配器模式(AdapterPattern)是将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作......
  • 【建造者设计模式详解】Java/JS/Go/Python/TS不同语言实现
    简介建造者模式(BuilderPattern),也叫生成器模式,属于创建型模式。它使用多个简单的对象一步一步构建成一个复杂的对象。它允许你使用相同的创建代码生成不同类型和形式的对......
  • 生产者消费者设计模式
    publicclassDemo{/*生产者步骤:*1、判断桌子上是否有汉堡包*2、如果有就等待,如果没有,就生产*3、把生产的汉堡包放到桌子上*4、唤醒......