设计模式
软件设计模式是一套反复使用,经验性的总结,具有一定普遍性,可以反复使用
1.软件设计原则
1.1开闭原则
对拓展开放,对修改关闭。在程序需要进行拓展时,不去修改原有的代码,实现一个热插拔的效果,简而言之,是为了使程序的拓展性好,易于维护和升级。
想要达到这样的效果,我们需要使用接口和抽象类。
因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。
1.2 里氏代换原则
里氏代换原则是面向对象设计的基本原则之一。
里氏代换原则:任何基类可以出现的地方,子类一定可以出现。通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能。换句话说,子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。
1.3 依赖倒转原则
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
2.创建型模式
-
单例模式
-
工厂方法模式
-
抽象工厂模式
-
原型模式
-
建造者模式
2.1 单例设计模式
单例模式是Java中最简单的设计模式之一,
2.1.1 单例模式的结构
- 单例类。只能创建一个实例的类
- 访问类。使用单例类
2.1.2 单例模式的实现
单例模式分两种:
饿汉式:类加载就会导致该单实例对象被创建
懒汉式:类加载不会导致该单实例对象被创建,首次使用该对象被创建
-
饿汉式
方式一(静态变量方式)
/** * @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基本上一样,当然该方式也存在内存浪费问题。
-
懒汉式
方式一:线程锁方式
说明:
该方式也实现了懒加载效果,同时又解决了线程安全问题。但是在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;
}
}
-
静态内部类方式
/** * @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 创建者模式
- 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于: 某个对象的构建过程复杂的情况
- 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象,相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
- 建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须道其内部的具体构造细节。
类图
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