设计模式
共有23中设计模式,Gof23。
-
GoF23
-
一种思维,一种态度,一种进步
-
-
创建型模式:(描述怎么创建一个对象)
-
单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
-
-
结构型模式:(描述类或对象按照某种布局组成一些更大的结果)
-
适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式
-
-
行为型模式:(描述类或者对象之间怎么相互协作去共同完成单个对象无法完成的工作)
-
模板方法模式,命令模式,迭代器模式,观察者模式,中介模式,备忘录模式,解释器模式,状态模式,策略模式,职责链模式,访问者模式
-
OOP七大原则(面向对象)
-
开闭原则:对扩展开放,对修改关闭
-
对一个类添加方法的时候,要避免修改这个类中之前的方法
-
-
里氏替换原则:继承必须确保超类所拥有的的也行在子类中仍然成立
-
不要修改父类中的方法,可以在子类中添加方法
-
正方形不是长方形
-
-
依赖倒置原则:要面向接口编程,不要面向实现编程
-
面向接口编程
-
抽象不依赖细节,细节依赖抽象
-
降低程序之间的耦合性
-
-
单一职责原则:控制类的粒度大小、将对象解耦、提高其内聚性
-
一个方法尽可能干好一件事情
-
原子性
-
-
接口隔离原则:要为各个类建立他们需要的专用接口
-
降低耦合
-
-
迪米特法则:只与你的直接朋友交谈,不跟”陌生人“说话
-
合成复用原则:尽量先使用组合或者聚合等关联关系来实现,期次才考虑使用继承关系来实现
创建型模式
单例模式
不要new对象
只要是单利模式一定构造器私有
-
恶汉式单例
初始化的时候就把类中所有的资源都加载到内存中,比较浪费资源
package com.wx.single;
/**
* @BelongsProject: wxStuSCB
* @BelongsPackage: com.wx.single
* @Author: wangxiang
* @CreateTime: 2022-10-18 12:04
* @Description: 恶汉式单列
* @Version: 1.0
* 浪费内存
*/
public class Hungry {
//可能会浪费空间
private byte[] bytes1 = new byte[1024*1024];
private byte[] bytes2 = new byte[1024*1024];
private byte[] bytes3 = new byte[1024*1024];
private byte[] bytes4 = new byte[1024*1024];
private Hungry(){
}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
}
-
DCL懒汉式单例
-
使用的时候进行创建
-
双重检测锁的模式
package com.wx.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @BelongsProject: wxStuSCB
* @BelongsPackage: com.wx.single
* @Author: wangxiang
* @CreateTime: 2022-10-18 12:09
* @Description: 懒汉式单列模式
* @Version: 1.0
*/
public class LazyMan {
private static boolean wx = false;
private LazyMan(){
synchronized (LazyMan.class){
if (!wx){
wx = true;
}else {
throw new RuntimeException("不用试图使用反射破坏");
}
}
}
private volatile static LazyMan lazyMan;
//普通模式
public static LazyMan getInstance1(){
if (lazyMan==null){
lazyMan = new LazyMan();
}
return lazyMan;
}
//双重检测锁的模式 懒汉式单列 DCL懒汉式
public static LazyMan getInstance(){
if (lazyMan==null){
synchronized (LazyMan.class){
if (lazyMan==null){
lazyMan = new LazyMan();//不是一个原子性操作
/**
1、分配内存空间
2、执行构造方法,初始化对象
3、把这个对象指向这个空间
理想情况下会按照1、2、3这个顺序执行
但是多线程下可能会有问题
A线程:按照1、3、2这个执行顺序执行了,指令重排
B线程:A线程在执行到第3步的时候lazyMan这个对象在内存空间中是有值的所以不是null,
但是这个时候A线程还没有执行第2步初始化操作,所以会有问题
解决方法:添加volatile关键字修饰
*/
}
}
}
return lazyMan;
}
//单线程下没问题
//多线程下会有问题
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// for (int i = 0; i <10 ; i++) {
// new Thread(()->{
// getInstance();
// }).start();
// }
LazyMan instance = LazyMan.getInstance();
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
//忽略私有构造器
declaredConstructor.setAccessible(true);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance);
System.out.println(instance2);
}
}
-
-
静态内部类
package com.wx.single;
/**
* @BelongsProject: wxStuSCB
* @BelongsPackage: com.wx.single
* @Author: wangxiang
* @CreateTime: 2022-10-18 12:30
* @Description: 静态内部类
* @Version: 1.0
*/
public class Holder {
private Holder(){
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private final static Holder HOLDER = new Holder();
}
}
-
单例不安全,因为可以通过反射创建对象
-
枚举
枚举中没有无参构造,只有有参构造。通过jad反编译查看,不用使用idea和javap反编译查看,会有问题
package com.wx.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @BelongsProject: wxStuSCB
* @BelongsPackage: com.wx.single
* @Author: wangxiang
* @CreateTime: 2022-10-18 12:42
* @Description: 枚举本身也是一个class类
* @Version: 1.0
*/
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
EnumSingle instance = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
EnumSingle instance1 = declaredConstructor.newInstance();
System.out.println(instance);
System.out.println(instance1);
}
}
工厂模式
-
作用:
-
实现了创建者和调用者的分离
-
详细分类:
-
简单工厂模式
-
工厂方法模式
-
抽象工厂模式
-
-
-
OOP七大原则
-
开闭原则:对扩展开放,对修改关闭
-
依赖倒置原则:要面向接口编程,不要面向实现编程
-
迪米特法则:只与你的直接朋友交谈,不跟”陌生人“说话
-
-
核心本质:
-
实例化对象不适用new,用工厂方法代替
-
将选择实现类,创建对象统一管理和控制。从而将调用者和我们的实现类解耦
-
-
三种模式:
-
简单工厂模式
-
用来生产同一等级结构中的任意产品(对于增加新的产品,需要扩展已有的代码)
-
-
工厂方法模式
-
用来生产同一等级结构中的固定产品(支持增加任意产品)
-
-
抽象工厂模式
-
围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂
-
根据设计原则:工厂方法模式
根据实际业务:简单工厂模式
-
抽象工厂模式
-
定义:抽象工厂模式提供了一个创建一系列相关或者相互依赖的接口,无需指定他们的具体类
-
适用场景:
-
客户端(应用层)不依赖于产品类实例如何被创建、实现等
-
强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的重复代码
-
提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现
-
-
优点:
-
具体产品在应用层的代码隔离,无需关心创建的细节
-
将一个系列的产品统一到一起创建
-
-
缺点:
-
规定勒索有可能被创建的产品集合,产品簇中扩展新的产品困难
-
正价了系统的抽象性和理解难度
-
通过idea查看类图:
选中包或类文件,右键,选中 Diagrams,然后选择 Show Diagram
选中 f 和 m 加粗样式这两个按钮,这样就展示了每个类的属性和方法,一目了然,点击 show dependencies
建造者模式
-
建造者模式也属于创建型模式,它提供了一种创建对象的最佳方式。
-
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同 的表示
-
主要作用:在用户不知道对象的的建造过程和细节的情况下就可以直接创建复杂的对象
-
用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
-
例子:
-
工厂(建造者模式):负责制造汽车(组装过程和细节在工厂内)
-
汽车购买者(用户):你需要说出你需要的型号(对象的类型和内容),然后直接购买就可以使用了(不需要知道汽车是怎么组装的(车轮,车门,发动机,方向盘等))
-
原型模式
-
克隆
-
Prototype
-
Cloneable接口
-
clone()方法
结构型模式
作用:
从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题。
适配器模式
-
USB网线转换器
代理模式
-
静态代理(每次代理一个角色都要把所有的方法重写,但是实现了业务分工)
角色分析:
-
抽象角色:一般会使用接口或者抽象类来解决
-
真是角色:被代理的角色
-
代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作
-
客户:访问代理对象的人
代码步骤:
-
接口
public interface Rent {
//出租房屋的方法
public void rent();
} -
真实角色
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子");
}
} -
代理角色
public class Proxy implements Rent {
private Host host;
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seyHouse();
System.out.print("中介帮你租房子");
host.rent();
receiveMoney(1235L);
}
public void seyHouse(){
System.out.println("中介带你看房");
}
public void receiveMoney(double money){
System.out.println("收取中介费:"+money);
}
} -
客户端访问代理
public class Client {
public static void main(String[] args) {
//直接租房
// Host host = new Host();
// host.rent();
//通过代理租房
Proxy proxy = new Proxy(new Host());
proxy.rent();
}
}
代理模式的好处:
-
可以使真是角色的操作更加纯粹,不用去关心业务
-
公共业务交给代理角色,实现了业务的分工
-
公共也放生扩展的时候,方便集中管理
缺点:
-
一个真实角色就会产生一个代理角色,代码量会翻倍;开发效率会降低
-
-
动态代理
-
动态代理和静态代理角色一样
-
动态代理的代理类是动态生成的,不是直接写好的
-
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
-
基于接口的---JDK动态代理
-
基于类:cglib
-
java字节码实现:javasist
-
需要了解两个类:Proxy(代理),InvocationHandler(调用处理程序)
动态代理的好处:
-
可以使真是角色的操作更加纯粹,不用去关心业务
-
公共业务交给代理角色,实现了业务的分工
-
公共也放生扩展的时候,方便集中管理
-
一个动态代理类代理的是一个接口,一般就是对应的一类业务
-
一个动态代理类可以代理多个类,只要是实现了同一个接口即可
-
桥接模式
装饰模式
组合模式
外观模式
享元模式
标签:class,代理,模式,public,new,设计模式,LazyMan From: https://www.cnblogs.com/wx-36/p/16914547.html