面向对象的设计模式
23种基础模式(持续更新)
每种模式都有与之对应的原理
单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。其属于创建型模式,它向我们提供一种创建对象的最佳方式。
其是将构造方法私有化,从而使得外部无法产生新的实例化对象,只能通过方法获取唯一的一个对象引用
特点:
1. 一个类中只有一个实例化对象
2. 必须自行创建实例
3. 必须在自行向整个系统提供实例
两种不同的形式:饿汉模式与懒汉模式
饿汉模式:即在创建对象时直接实例化。 ”线程安全“
public class SingletonMode {
//创建唯一的静态实例
private static SingletonMode instance = new SingletonMode();
//私有化构造方法
private SingletonMode(){
}
//创建获取方法
public static SingletonMode getInstance() {
return instance;
}
}
它是一种空间换时间的做法,无论你是否使用该实例,我先创建好该实例,使用时直接调用便好,这样在调用过程中就省去了开辟空间的操作了,可以节省时间,但不用是又造成垃圾产生。
使用场景:
- 如果在构造方法里写了性能消耗较大,占时较久的代码,比如建立与数据库的连接,那么就会在启动的时候感觉稍微有些卡顿
- 无论是否使用这个对象都立即加载
懒汉模式:需要调用对象是在实例化。 ”非线程安全“
public class SingletonMode {
private static SingletonMode instance;
private SingletonMode(){
}
public static SingletonMode getInstance() {
if (instance == null){
instance = new SingletonMode();
}
return instance;
}
}
是一种时间换空间的做法,调用时在创建。
看业务需求,如果业务有比较充分的启动和初始化时间,就使用饿汉模式,否则就使用懒汉模式
单例模式优点:
- 内存中只有一个对象
- 避免频繁的创建销毁对象,提高了性能
- 避免对共享资源的多重占用
缺点:
- 扩展比较困难
- 若实例化后的对象长期不用,系统会默认其为垃圾并进行回收,造成对象状态丢失。
使用场景:
1、创建对象时占用资源过多,但同时又需要用到该类对象
2、对系统内资源要求统一读写,如:读写配置信息
3、当多个实例存在可能引起程序逻辑错误,如:号码生成器
建造者模式
概念:又叫生成器模式,是一种对象构建模式(也就是创建型模式)。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
建造者模式就是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以建造他们,用户不需要知道内部的具体构建细节
建造者模式的四个角色:
- Product(产品角色):一个具体的产品
- Builder(抽象建造者):创建一个Product对象的各个部件指定的接口或抽象类(将实现某一类具体物品或者是实体时这些东西所具有的共性抽取出来的抽象方法)
- ConcreteBuilder(具体建造者):实现接口,构建和装配各个部件
- Director(指挥者):构建一个使用Builer接口的对象。它主要用于创建一个复杂的对象。两个作用:1、隔离了客户与对象生产的过程。2、负责控制产品对象的生产过程
通过一个盖房的实例来解释一下什么是建造者模式
需求:
- 需要建房子:这一过程为打地基、砌墙、封顶
- 建造一个普通房,一个高楼
对于传统的放式,我们只需要将普通房子与高楼共同的特征抽象出来组成一个抽象类,然后在抽象类有一个建造方法 ,将两个房子的建造过程组合一下。然后在一个客户类中去实例化两个房子。比较简单直观,下面是传统方式的类图:
相信通过类图大家应该都能看明白,下面我们来看一下建造者模式下这个过程:
类图:
具体代码:
public class House {
//产品类
private String basic;
private String wall;
private String roof;
public String getBasic() {
return basic;
}
public void setBasic(String basic) {
this.basic = basic;
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getRoof() {
return roof;
}
public void setRoof(String roof) {
this.roof = roof;
}
}
public abstract class BuilderHouse {
//抽象建造者
House house = new House();
public abstract void buildBasic();
public abstract void buildWall();
public abstract void buildRoof();
public House buildHouse() {
return house;
}
}
//具体建造者
public class CommonHouse extends BuilderHouse{
@Override
public void buildBasic() {
System.out.println("普通房子打地基");
}
@Override
public void buildWall() {
System.out.println("普通房子砌墙");
}
@Override
public void buildRoof() {
System.out.println("普通房子封顶");
}
}
//指挥者
public class HouseDirector {
private BuilderHouse bh;
//写一个构造器,将
public HouseDirector(BuilderHouse bh){
this.bh = bh;
}
//通过setter 传入builderHouse
public void setBh(BuilderHouse bh) {
this.bh = bh;
}
//将房子的建造流程, 交给指挥者
public House constructHouse(){
bh.buildBasic();
bh.buildWall();
bh.buildRoof();
return bh.buildHouse();
}
}
public class Client {
public static void main(String[] args) {
//建造普通房子
CommonHouse commonHouse = new CommonHouse();
// 创建房子的指挥者
HouseDirector houseDirector = new HouseDirector(commonHouse);
//完成盖房操作
houseDirector.constructHouse();
}
}
运行图:
仔细观看整个过程的代码会发现,我们在创建普通房子时是将整个房子的建造过程交给了指挥者去完成,而在用户类中只需要告诉指挥者我现在需要建造什么,然后在客户类中去调用指挥者从而创建这个对象。
建造者模式中需要注意的事项
- 客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
- 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象
- 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程
- 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统更方便扩展,符合“开闭原则”
缺点
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,因此在这种情况下,要考虑是否选择建造者模式
应用场景
- 相同的方法,不同的执行顺序,产生不同的结果。
- 多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同。
- 产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用。
- 初始化一个对象特别复杂,参数多,而且很多参数都具有默认值
建造者模式和工厂模式的区别
- 建造者模式根据建造过程中的顺序不一样,最终对象部件组成也不一样
- 关注重点不一样,工厂模式只需要把对象创建出来就可以了,而建造者模式不仅要创建出对象,还要知道对象由哪些部件组成。