编程设计模式详解

设计模式六大原则

●开闭原则

​ 对扩展开放,对修改关闭,在代码层面而言就是在你有新的需求的时候,你应当增加新的对象来实现,而不是修改原来的对象

​ 继承

●里氏替换原则

​ 基类可以出现,那么子类一定也能行

  • 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法
  • 子类中可以增加自己特有的方法
  • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格

接口隔离原则

用多个专门的接口比使用单一的总接口要好。一个类对另外一个类的依赖性应当是建立在最小的接口上的;

一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。

举个栗子:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。

解决方案:将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系

●依赖倒转原则

​ 针对接口编程

高层模块不应该依赖低层模块,两者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象

也就是说,尽量依赖接口,不要依赖细节

例如:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。

解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。

●迪米特法则,最少知道原则

​ 减少耦合

又叫做最少知道原则,就是说一个对象应当对其它对象有尽可能少的了解,类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大,所以一个对象应该对其他对象保持最少的了解,也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息,迪米特法则初衷在于降低类之间的耦合。由于每个类尽量减少对其它类的依赖,因此。很容易使得系统的功能模块独立,相互之间不存在(或很少代码体现有)依赖关系。

举个栗子:Leader想从Teacher那里知道现有Student的的总数,它们之间的调用关系应该为Leader—>Teacher—>Student,Leader与Student并无直接联系,所以在Leader类的方法中不应该出现Student类

合成复用原则

尽量合成或者聚合而不是继承

模板方法模式:

Spring中jdbcTemplate、hibernateTemplate 等以Template结尾的对数据库操作的类,它们就使用到了模板模式。

包装器设计模式:

我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。

工厂模式

工厂设计模式: Spring使用工厂模式通过BeanFactory、ApplicationContext 创建bean对象。

简单工厂:一个工厂类根据传入的参数决定创建出那一种产品类的实例。

优点:创建对象分离开,解耦,工厂负责创建对象,程序员只需要去调用就行。

创建一个汽车的接口,定义一个汽车名字的方法,然后定义几个品牌类去实现这个接口,

然后去写一个工厂

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bUnncBVE-1670295589080)(…/img/image-20220831145555660.png)]

当时当想给添加别的汽车品牌的时候,就需要添加代码,违反开闭原则,需要修改工厂的代码

缺点:当我们新增类的时候,需要去修改工厂配置,增加创建对象的分支,每次都要去修改

抽象工厂模式:

工厂的工厂:一个大工厂,里面有具体的不同产品的小工厂,每个生成的工厂都能按照简单工厂模式提供对象,他们自己决定生产哪一些产品

比如苹果有创建苹果的工厂,各自有各自的工厂,免除了简单工厂模式的每次新增就会修改工厂代码,各自负责自己的工厂创建,每个工厂决定到底生产哪些产品

单例模式

单例设计模式:Spring中的Bean默认都是单例的。

概念

全世界就只要一个—在整个java程序中,只有这个类的一个实例

比如Student a = new Student(); 就是Student类只创建这一个实例,只能有这一个对象存在

主要解决:一个全局使用的类频繁地创建与销毁。在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)

何时使用:当您想控制实例数目,节省系统资源的时候。

关键代码:构造函数是私有的。

1、为了保证只有一个对象,不能new对象,所以设置构造方法私有。

2、只能通过方法或者属性获取对象,如果通过属性获取,这个属性是可以修改的,所以属性只能

是私有的。所以只能通过方法获取。

3、由于我们不能new对象,所以获取对象的方法定是静态的。属性也得是静态的,因为不是静态的,静态的方法访问不到

**缺点:**没有接口,不能继承,与单一 职责原则冲突,一 个类应该只关心内部逻辑, 而不关心外面怎么样来实例化。

使用场景:

  • 1、要求生产唯一序列号。
  • 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
  • 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

**注意事项:**getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。

**枚举:**对象固定,私有构造器

饿汉

类加载后一开始就会创建对象,

缺点就是占内存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ZQ7CksV-1670295589081)(…/img/image-20220831165809527.png)]

懒汉模式

需要的时候才会去创建对象

好处:节省内存 坏处用的时候才创建稍微有点慢

线程不安全,当创建了100个线程,调用getInstance方法时,可能会有多个线程同时看到没有new,就会执行多次new,调用多次构造方法(也就是会进行多次初始化)

线程安全 给getInstance方法加synchronize锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kf8Pfus0-1670295589082)(…/img/image-20220831165549693.png)]

双重校验锁–安全的懒汉式

我们可以选择不给getInstance方法加synchronize锁,而是在这个方法里面去进行加synchronize锁,因为方法锁的范围太广,其他线程阻塞的范围就大,时间就长。

双锁是懒汉为了解决线程安全演变来的

当多线程调用getInstance,不知道是不是第一次调用,有没有创建对象,所以要判断一下属性是否为空

为空需要创建对象,但是在多线程的情况下,访问这个方法的情况下,多个线程可能会创建多个对象,就不是单例了

所以在判断是不是为空后,需要给这个对象加synchronize锁。

假设第一个线程执行完,接下来的线程就会来进行竞争锁,它还是要继续判断是否为空,不为空,直接return

synchroniz不能防止指令重排序,instance = new Instance () ;可能会发生指令重排序,就是另一个线程会访问到Instance 仍然为空,再次进入到第一个if循环

类属性加volatile的原因:第一个线程加锁之后创建了对象,能够让其他线程及时发现 instance 不是空了,这样其他线程就不用进入第一层判断了,加快了程序速度;如果没有加volatile,不能防止指令重排序,可能对象创建了,但是句柄的地址没有传给属性,判断时还是空,这样就需要继续走第一层if。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F2yfo0tB-1670295589082)(…/img/image-20220905152440380.png)]

建造者模式

它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成.

建造者模式包括的角色:

(1)Builder:给出一个抽象接口或抽象类,以规范产品的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建,一般由子类具体实现。

(2)ConcreteBuilder:Builder接口的实现类,并返回组建好对象实例

(3**)Director(指挥者):调用具体建造者来创建复杂对象的各个部分**,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

(4)Product:要创建的复杂对象,产品类。

建造者模式的使用场景:

(1)当产品有复杂的内部构造时(参数很多)。

(2)需要生产的产品的属性相互依赖,这些属性的赋值顺序比较重要时(因为在调用ConcreteBuilder的赋值方法时是有先后顺序的)。

建造者模式优缺点

建造者模式的优点:

(1)建造模式是将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心,良好的封装性是建造者模式的优点之一。

(2)建造者类逻辑独立,易拓·1`展。

建造者模式的缺点:

很明显产生了多余的Build对象以及Dirextor对象,消耗了内存。

要组装一台电脑(Computer类),我们假设它有三个部件:CPU 、主板以及内存。

在Computer类中提供三个set方法分别设置这三个属性。
public class Computer {
    private String mCpu;
    private String mMainboard;
    private String mRam;
 
    public void setmCpu(String mCpu) {
        this.mCpu = mCpu;
    }
 
    public void setmMainboard(String mMainboard) {
        this.mMainboard = mMainboard;
    }
 
    public void setmRam(String mRam) {
        this.mRam = mRam;
    }
}
Builder类	
里面提供了安装CPU、主板和内存的抽象方法,以及组装成电脑的create方法
public abstract class Builder {
    public abstract void buildCpu(String cpu);
    public abstract void buildMainboard(String mainboard);
    public abstract void buildRam(String ram);
    public abstract Computer create();
}
Builder实现类
里面不仅新建了Computer的实例,还提供了安装CPU、主板和内存的具体实现方法,并且在组装成电脑的create方法中将该Computer对象实例返回
public class MyComputerBuilder extends Builder {
    private Computer mComputer = new Computer();
    @Override
    public void buildCpu(String cpu) {
        mComputer.setmCpu(cpu);
    }
 
    @Override
    public void buildMainboard(String mainboard) {
        mComputer.setmMainboard(mainboard);
    }
 
    @Override
    public void buildRam(String ram) {
        mComputer.setmRam(ram);
    }
 
    @Override
    public Computer create() {
        return mComputer;
    }
}
指挥者(Director)类用来规范组装电脑的流程顺序,先安装主板,再安装CPU,最后安装内存并组装成电脑。
public class Direcror {
    Builder mBuild=null;
    public Direcror(Builder build){
        this.mBuild=build;
    }
    public Computer CreateComputer(String cpu,String mainboard,String ram){
        //规范建造流程,这个顺序是由它定的
       this.mBuild.buildMainboard(mainboard);
       this.mBuild.buildCpu(cpu);
       this.mBuild.buildRam(ram);
       return mBuild.create();
    }
}
Builder mBuilder = new MyComputerBuilder();
Direcror mDirecror=new Direcror(mBuilder);
mDirecror.CreateComputer("i7","Intel主板","mRam");//返回Computer实例对象

观察者模式

定义对象间的一种一对多的关系,当一个对象状态发生改变时,所有依赖这个对象的都会得到通知,自动更新,比如微信的订阅,当作者发文则通知订阅者。

观察者模式: Spring事件驱动模型就是观察者模式很经典的一-个应用。

代理模式

代理设计模式**:SpringAOP功能的实现。**动态代理

适配器模式

适配器模式:SpringAOP的增强或通知(Advice)使用到了适配器模式、springMVC中也是用到了适配器模式适配Controller。

责任链模式

项目中责任链模式也比较常用,从其概念可以看出其适合的应用场景:链!

避免将一个请求的发送者和接收者耦合在一起,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。
解耦,不仅是该模式的作用和特点,更是软件设计的原则之一。如何来判定某个对象是否有机会处理链上的请求,这个判断的过程是不是像极了过滤器?所以过滤器的设计可以说是该模式的一个特点。

此外,采用职责链模式不仅可以方便扩展(当增加一个接受者时,只需要在链上的适当位置插入对应的处理方法即可),而且可以替换掉代码中可能存在的switch-case或者if-else,从代码简洁的考量也是一个不错的回答角度。(当然,替换掉switch-case或if-else不仅仅只有这种设计模式可以达到)

请求的发送者和接收者耦合在一起,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。
解耦,不仅是该模式的作用和特点,更是软件设计的原则之一。如何来判定某个对象是否有机会处理链上的请求,这个判断的过程是不是像极了过滤器?所以过滤器的设计可以说是该模式的一个特点。

此外,采用职责链模式不仅可以方便扩展(当增加一个接受者时,只需要在链上的适当位置插入对应的处理方法即可),而且可以替换掉代码中可能存在的switch-case或者if-else,从代码简洁的考量也是一个不错的回答角度。(当然,替换掉switch-case或if-else不仅仅只有这种设计模式可以达到)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值