设计模式
1: 单列模式
单列模式是保证系统唯一性的重要的手段,单列模式首先通过把类的构造器私有化来防止程序通过其它的方式创建该类的实列,然后通过提供一个全局的唯一方法来帮助用户来获得该类的实例,用户只需要也只能通过调用该方法获得该类实列
常见的方法:1、懒汉模式 2、饿汉模式 3、双重校验锁 4 静态内部类等实现方式
懒汉式,线程不安全
是否 Lazy 初始化:是
是否多线程安全:否
实现难度:易
描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉式,线程安全
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:易
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式
是否 Lazy 初始化:否
是否多线程安全:是
实现难度:易
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
在类加载时已经创建了单例对象,并且它是由static final 修饰的,保证了单例对象在整个程序中都只有一个实例,所以不会有性能问题,并且也不需要额外的同步操作来保证线程安全。但是饿汉式单例在类加载时就创建了单例对象,因此在某些场景下可能会造成内存浪费。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
双检锁/双重校验锁(DCL,即 double-checked locking)
JDK 版本:JDK1.5 起
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:较复杂
描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。
从运行结果可以看出,如果不进行第二次判空的话,那么在竟锁池(锁池)中如果还有活跃的线程在等待获取的锁的话,在锁释放后就会再次竞争获取锁,获取的锁的线程进入"就绪状态",
当cpu分配其"时间片"后进行线程的调度,从而线程进入"运行中状态",并会去执行同步的代码块,如果在没加如二次判空的话,就会导致系统中存在多个实例,
而在进行判空后,即使你获取到了锁,但在执行同步代码块时也会直接跳过。
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
2: 建造者(Builder)模式
建造者(Builder)模式的定义:将组件和组件的组装过程分开,然后⼀步⼀步建造⼀个复杂的对象,在项目中常用来创建实体类,
在要构造的类内部创建一个静态对象类builder;、
静态内部类的参数和构建类一致;
直接调用建造者对应的方法,为对应的属性赋值
最后只要调用建造者提供的build方法即可根据我们的配置返回一个对象
class Pizza {
private String size;
private boolean cheese;
private boolean pepperoni;
private boolean bacon;
public Pizza(String size, boolean cheese, boolean pepperoni, boolean bacon) {
this.size = size;
this.cheese = cheese;
this.pepperoni = pepperoni;
this.bacon = bacon;
}
// 省略getter和setter方法
}
class PizzaBuilder {
private String size;
private boolean cheese;
private boolean pepperoni;
private boolean bacon;
public PizzaBuilder setSize(String size) {
this.size = size;
return this;
}
public PizzaBuilder addCheese() {
this.cheese = true;
return this;
}
public PizzaBuilder addPepperoni() {
this.pepperoni = true;
return this;
}
public PizzaBuilder addBacon() {
this.bacon = true;
return this;
}
public Pizza build() {
return new Pizza(size, cheese, pepperoni, bacon);
}
}
PizzaBuilder pizzaBuilder = new PizzaBuilder();
Pizza pizza = pizzaBuilder.setSize("大")
.addCheese()
.addPepperoni()
.addBacon()
.build();
System.out.println("您的披萨:大小-" + pizza.getSize() +
",奶酪-" + pizza.isCheese() +
",意式辣香肠-" + pizza.isPepperoni() +
",培根-" + pizza.isBacon());
3:模板方法
提供了一个抽象类,将部分逻辑以具体的方法的形式实现,然后声名一些抽象的方法来迫使子类实现的逻辑,不同的子类可以通过不同的方式实现这些抽象的方法,从而实现不同的业务逻辑。
假设我们有一个游戏类 Game,其中包含游戏的初始化、开始、结束等流程。我们希望在游戏的开始和结束时,能够分别打印不同的消息。我们可以使用模板方法模式来实现这个功能。
首先,定义游戏抽象类 Game:
// 游戏抽象类
abstract class Game {
// 初始化游戏
abstract void initialize();
// 开始游戏
abstract void startPlay();
// 结束游戏
abstract void endPlay();
// 模板方法,定义游戏流程
public final void play() {
initialize();
startPlay();
endPlay();
}
}
然后,创建具体的游戏类 FootballGame 和 BasketballGame:
// 具体的足球游戏类
class FootballGame extends Game {
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
}
// 具体的篮球游戏类
class BasketballGame extends Game {
@Override
void initialize() {
System.out.println("Basketball Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Basketball Game Started. Enjoy the game!");
}
@Override
void endPlay() {
System.out.println("Basketball Game Finished!");
}
}
最后,在客户端代码中使用模板方法模式:
// 客户端代码
public class Client {
public static void main(String[] args) {
Game footballGame = new FootballGame();
Game basketballGame = new BasketballGame();
System.out.println("Football Game:");
footballGame.play();
System.out.println("\nBasketball Game:");
basketballGame.play();
}
}
4: 外观模式
提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统使用更加容易
示例:创建一个外观类 ComputerFacade,它封装了计算机系统的一组复杂接口,包括 CPU、内存和硬盘的启动和关闭操作。
5: 策略模式
策略模式为同一个行为定义了不同的策略,并为每种策略都实现了不同的方法.使用策略模式可以避免使用多重条件if…else if…else语句,
策略模式的主要角色如下
抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
环境(Context)类:持有一个策略类的引用,环境角色使用抽象策略(Strategy)类接口调用不同的算法,最终给客户端调用。
6: 工厂模式
工厂模式在接口中定义了创建对象的方法,而将具体的创建对象的过程在子类中实现,用户只需通过接口创建需要的对象即可,不用关注对象的具体创建过程。同时,不同的子类可根据需求灵活实现创建对象的不同方法
7: 原型模式
原型(Prototype)模式的定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象
原型模式的克隆分为浅克隆和深克隆。
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
8: 适配器模式
适配器模式(Adapter)的定义如下:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式、对象结构型模式和接口适配器模式
适配器模式(Adapter)包含以下主要角色。
目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
9:装饰器模式
不改变原来代码和继承关系的情况下,动态的扩张类的功能,如框架controller文件提供before和after方法
装饰者模式包括source(被装饰类)和decorator(装饰类)
10: 迭代器模式
提供了一个方法顺序访问一个聚合对象中各个元素,又不需要暴露该对象的内部表示
11: 代理模式
代理模式指为对象提供一种通过代理的方式访问并控制该对象行为的方法,通过代理控制对象的访问,可以再这个对象调用方法之前去处理、添加新功能
12: 桥接模式
桥接模式通过将抽象及其实现解耦,使得两者可以根据需求独立变化,通过定义一个抽象和实现之前的桥接 者来达到解耦的目的
桥接模式主要用于解决需求多变的情况下使用继承造成爆炸的问题,扩展起来不够灵活
13: 组合模式
主要用于实现部分和整体操作的一致性,组合模式常根据树型结构表示部分及整体的关系
14: 享元模式
主要通过对象的复用来减少对象的创建的次数和数量,减少系统内存的使用和减低系统的负载
15:观察者模式
观察者模式指被观察者的状态发生变化时,系统基于时间驱动理论将其状态通知到订阅其状态的观察者中,用以完成状态的修改和事件的传播
16: 责任链模式
为了避免请求发送者与多个请求处理者耦合在一起,责任链模式让所有的请求处理者持有下一个对象的引用,从而将请求串联成一条链,在有请求发生的时候,可以将请求沿着这条链传递,直到遇到该对象的处理器
手写23设计模式:

浙公网安备 33010602011771号