【设计模式——学习笔记】23种设计模式——备忘录模式Memento(原理讲解+应用场景介绍+案例介绍+Java代码实现)

简介: 【设计模式——学习笔记】23种设计模式——备忘录模式Memento(原理讲解+应用场景介绍+案例介绍+Java代码实现)

案例引入

游戏角色有攻击力和防御力,在大战Boss前保存自身的状态(攻击力和防御力),当大战Boss后攻击力和防御力下降,可以从备忘录对象恢复到大战前的状态

传统设计方案

针对每一种角色,设计一个类来存储该角色的状态

【分析】

  • 一个对象,就对应一个保存对象状态的对象, 这样当我们游戏的对象很多时,不利于管理,开销也很大
  • 传统的方式是简单地做备份,new出另外一个对象出来,再把需要备份的数据放到这个新对象,但是这样暴露了对象内部的细节
  • 优化方式:使用备忘录模式

介绍

基本介绍

  • 备忘录模式在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态
  • 可以这样理解备忘录模式: 现实生活中的备忘录是用来记录某些要去做的事情或者是记录已经达成的共同意见的事情,以防忘记。而在软件层面,备忘录对象主要用来记录一个对象的某种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作
  • 备忘录模式属于行为型模式

登场角色

  • Originator(生成者):Originator角色会在保存自己的最新状态时生成Memento角色。当把以前保存的Memento角色传递给Originator角色时,它会将自已恢复至生成该Memento角色时的状态
  • Memento(备忘录):Memento角色会将Originator 角色的内部信息整合在一起。在 Memento 角色中虽然保存了Originator 角色的信息,但它不会向外部公开这些信息(通过对方法的权限字符进行设置)
  • Caretaker(负责人):当Caretaker角色想要保存当前的Originator角色的状态时,会通知Originator角色Originator角色在接收到通知后会生成Memento角色的实例并将其返回给Caretaker角色。由于以后可能会用Memento实例来将Originator恢复至原来的状态,因此Caretaker角色会一直保存 Memento实例在示例程序中。Caretaker角色只能使用Memento角色的两种接口(API)中的窄接口,也就是说它无法访Memento角色内部的所有信息(比如案例三中Caretaker角色只能获取Memento角色的金钱信息,无法进行创建Memento实例等操作)。它只是将Originator角色生成的Memento角色当作一个黑盒子保存起来。虽然Originator角色Memento角色之间是强关联关系,但Caretaker角色Memento角色之间是弱关联关系。Memento角色Caretaker角色隐藏了自身的内部信息

【划分Caretaker角色Originator角色的意义】

Caretaker角色的职责是决定何时拍摄快照,何时撤销以及保存Memento角色。另一方面,Originator 角色的职责则是生成Memento角色和使用接收到的Memento角色来恢复自己的状态。有了这样的职责分担,当我们需要应对以下的需求变更时,就不用修改Originator角色

  • 变更为可以多次撤销
  • 变更为不仅可以撤销,还可以将现在的状态保存在文件中

【Caretaker角色只能通过窄接口(API)来操作 Memento角色,如果Caretaker角色可以随意地操作Memento角色,会发生什么问题呢】

  • 破坏对象的封装性:Memento角色负责存储Originator角色的状态数据,如果Caretaker角色可以随意地操作Memento角色,那么就破坏了Memento对象和Originator对象的封装性
  • 不安全的状态恢复:如果Caretaker角色可以随意地操作Memento角色,可能会改变Memento对象中存储的状态数据,导致状态恢复产生错误
  • 无法保证数据的完整性:如果Caretaker角色可以随意地操作Memento角色,可能会在不正确的时间点保存状态数据,导致数据的不完整性

案例实现

案例一(基础案例)

类图

  • Originator:需要被保存状态的对象
  • Memento:备忘录对象,负责记录Originator对象的状态
  • Caretaker:守护者对象,负责保存多个备忘录对象,一般使用集合进行管理,提高管理效率

实现

【Originator】

package com.atguigu.memento.theory;
public class Originator {
    /**
     * 角色的状态信息
     */
    private String state;
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    /**
     * 编写一个方法,可以保存一个状态对象 Memento
     * 因此编写一个方法,返回 Memento
     *
     * @return
     */
    public Memento saveStateMemento() {
        return new Memento(state);
    }
    /**
     * 通过备忘录对象获取原有状态信息,恢复状态
     *
     * @param memento
     */
    public void getStateFromMemento(Memento memento) {
        state = memento.getState();
    }
}

【Memento】

package com.atguigu.memento.theory;
public class Memento {
    /**
     * 用来保存状态信息
     */
    private String state;
    /**
     * 构造器
     *
     * @param state
     */
    public Memento(String state) {
        super();
        this.state = state;
    }
    /**
     * 获取保存的状态信息
     * @return
     */
    public String getState() {
        return state;
    }
}

【Caretaker】

package com.atguigu.memento.theory;
import java.util.ArrayList;
import java.util.List;
/**
 * 统一管理备忘录对象
 */
public class Caretaker {
    /**
     * 在 List 集合中会有很多的备忘录对象
     * 如果想要保存多个Originator的多个状态,可以使用HashMap<Originator的ID,List<Memento>>
     */
    private List<Memento> mementoList = new ArrayList<Memento>();
    public void add(Memento memento) {
        mementoList.add(memento);
    }
    /**
     * 获取 Originator 的 第 index 个 备忘录对象(即所保存的状态)
     *
     * @param index
     * @return
     */
    public Memento get(int index) {
        return mementoList.get(index);
    }
}

【主类】

package com.atguigu.memento.theory;
public class Client {
   public static void main(String[] args) {
      Originator originator = new Originator();
      // 备忘录对象管理器
      Caretaker caretaker = new Caretaker();
      originator.setState(" 状态#1 攻击力 100 ");
      //保存了当前的状态
      caretaker.add(originator.saveStateMemento());
      originator.setState(" 状态#2 攻击力 80 ");
      caretaker.add(originator.saveStateMemento());
      originator.setState(" 状态#3 攻击力 50 ");
      caretaker.add(originator.saveStateMemento());
      System.out.println("当前的状态是 =" + originator.getState());
      //希望得到状态 1, 将 originator 恢复到状态1
      originator.getStateFromMemento(caretaker.get(0));
      System.out.println("恢复到状态1 , 当前的状态是 =" + originator.getState());
   }
}

【运行】

当前的状态是 = 状态#3 攻击力 50 
恢复到状态1 , 当前的状态是 = 状态#1 攻击力 100 
Process finished with exit code 0

案例二

类图

实现

【Originator:GameRole】

package com.atguigu.memento.game;
public class GameRole {
    private int vit;
    private int def;
    /**
     * 创建Memento,即根据当前的状态得到Memento
     *
     * @return
     */
    public Memento createMemento() {
        return new Memento(vit, def);
    }
    /**
     * 从备忘录对象,恢复GameRole的状态
     *
     * @param memento
     */
    public void recoverGameRoleFromMemento(Memento memento) {
        this.vit = memento.getVit();
        this.def = memento.getDef();
    }
    /**
     * 显示当前游戏角色的状态
     */
    public void display() {
        System.out.println("游戏角色当前的攻击力:" + this.vit + " 防御力: " + this.def);
    }
    public int getVit() {
        return vit;
    }
    public void setVit(int vit) {
        this.vit = vit;
    }
    public int getDef() {
        return def;
    }
    public void setDef(int def) {
        this.def = def;
    }
}

【Memento】

package com.atguigu.memento.game;
public class Memento {
    /**
     * 攻击力
     */
    private int vit;
    /**
     * 防御力
     */
    private int def;
    public Memento(int vit, int def) {
        this.vit = vit;
        this.def = def;
    }
    public int getVit() {
        return vit;
    }
    public void setVit(int vit) {
        this.vit = vit;
    }
    public int getDef() {
        return def;
    }
    public void setDef(int def) {
        this.def = def;
    }
}

【Memento】

package com.atguigu.memento.game;
public class Memento {
    /**
     * 攻击力
     */
    private int vit;
    /**
     * 防御力
     */
    private int def;
    public Memento(int vit, int def) {
        this.vit = vit;
        this.def = def;
    }
    public int getVit() {
        return vit;
    }
    public void setVit(int vit) {
        this.vit = vit;
    }
    public int getDef() {
        return def;
    }
    public void setDef(int def) {
        this.def = def;
    }
}

【Caretaker】

package com.atguigu.memento.game;
/**
 * 守护者对象, 保存游戏角色的状态
 */
public class Caretaker {
    /**
     * 因为大战Boss之前只有一个状态,所以这里保存一次状态,不需要使用集合
     */
    private Memento memento;
    //对GameRole保存多次状态
    //private ArrayList<Memento> mementos;
    //对多个GameRole保存多个状态
    //private HashMap<String, ArrayList<Memento>> rolesMementos;
    public Memento getMemento() {
        return memento;
    }
    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

【主类】

package com.atguigu.memento.game;
public class Client {
   public static void main(String[] args) {
      //创建游戏角色
      GameRole gameRole = new GameRole();
      gameRole.setVit(100);
      gameRole.setDef(100);
      System.out.println("和boss大战前的状态");
      gameRole.display();
      //把当前状态保存caretaker
      Caretaker caretaker = new Caretaker();
      caretaker.setMemento(gameRole.createMemento());
      System.out.println("和boss大战~~~");
      gameRole.setDef(30);
      gameRole.setVit(30);
      gameRole.display();
      System.out.println("大战后,使用备忘录对象恢复到站前");
      gameRole.recoverGameRoleFromMemento(caretaker.getMemento());
      System.out.println("恢复后的状态");
      gameRole.display();
   }
}

【运行】

和boss大战前的状态
游戏角色当前的攻击力:100 防御力: 100
和boss大战~~~
游戏角色当前的攻击力:30 防御力: 30
大战后,使用备忘录对象恢复到站前
恢复后的状态
游戏角色当前的攻击力:100 防御力: 100
Process finished with exit code 0

案例三

案例说明

  • 游戏是自动进行的的金钱会增加
  • 当骰子点数为2的时候,主人公的金钱会减少
  • 当骰子点数为6的时候,主人公会得到水果
  • 主人公没有钱时游戏就会结束
  • 游戏的主人公通过掷骰子来决定下一个状态
  • 当骰子点数为1的时候,主人公

类图

实现

【Originator:Gamer】

package com.atguigu.memento.Sample.game;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
public class Gamer {
    /**
     * 所持金钱
     */
    private int money;
    /**
     * 获得的水果
     */
    private List fruits = new ArrayList();
    /**
     * 随机数生成器
     */
    private Random random = new Random();
    /**
     * 表示水果种类的数组
     */
    private static String[] fruitsName = {
            "苹果", "葡萄", "香蕉", "橘子",
    };
    /**
     * 构造函数
     *
     * @param money
     */
    public Gamer(int money) {
        this.money = money;
    }
    /**
     * 获取当前所持金钱
     *
     * @return
     */
    public int getMoney() {
        return money;
    }
    /**
     * 投掷骰子进行游戏
     */
    public void bet() {
        // 掷骰子,随机获取一个点数
        int dice = random.nextInt(6) + 1;
        if (dice == 1) {
            //  骰子结果为1…增加所持金钱
            money += 100;
            System.out.println("所持金钱增加了。");
        } else if (dice == 2) {
            // 骰子结果为2…所持金钱减半
            money /= 2;
            System.out.println("所持金钱减半了。");
        } else if (dice == 6) {
            // 骰子结果为6…获得水果
            String f = getFruit();
            System.out.println("获得了水果(" + f + ")。");
            fruits.add(f);
        } else {
            // 骰子结果为3、4、5则什么都不会发生
            System.out.println("什么都没有发生。");
        }
    }
    /**
     * 拍摄快照
     *
     * @return
     */
    public Memento createMemento() {
        Memento m = new Memento(money);
        Iterator it = fruits.iterator();
        while (it.hasNext()) {
            String f = (String) it.next();
            if (f.startsWith("好吃的")) {
                // 只保存好吃的水果
                m.addFruit(f);
            }
        }
        return m;
    }
    /**
     * 撤销到指定状态
     *
     * @param memento
     */
    public void restoreMemento(Memento memento) {
        this.money = memento.money;
        this.fruits = memento.getFruits();
    }
    /**
     * 用字符串输出主人公的状态
     *
     * @return
     */
    public String toString() {
        return "[money = " + money + ", fruits = " + fruits + "]";
    }
    /**
     * 随机获取一个水果
     *
     * @return
     */
    private String getFruit() {
        String prefix = "";
        if (random.nextBoolean()) {
            prefix = "好吃的";
        }
        return prefix + fruitsName[random.nextInt(fruitsName.length)];
    }
}

【Memento】

package com.atguigu.memento.Sample.game;
import java.util.ArrayList;
import java.util.List;
public class Memento {
    /**
     * 游戏主人公所持金钱
     */
    int money;
    /**
     * 游戏主人公当前获得的水果
     */
    ArrayList fruits;
    /**
     * 获取当前所持金钱(narrow interface)
     * narrow interface:Memento角色为外部的 Caretaker 角色提供了“窄接口(API)”。可以通过窄接口(API)获取的Memento角色的内部信息非常有限,因此可以有效地防止信息泄露
     * @return
     */
    public int getMoney() {
        return money;
    }
    /**
     * 构造函数(wide interface),只有相同包的Gamer类才使用该构造方法,因为方法修饰类型是default
     *
     * @param money
     */
    Memento(int money) {
        this.money = money;
        this.fruits = new ArrayList();
    }
    /**
     * 添加水果(wide interface)
     *
     * @param fruit
     */
    void addFruit(String fruit) {
        fruits.add(fruit);
    }
    /**
     * 获取当前所持所有水果(wide interface)
     * wide interface:“宽接口(API)”是指所有用于获取恢复对象状态信息的方法的集合。由于宽接口(API)会暴露所有Memento角色的内部信息,因此能够使用宽接口(API)的只有Originator 角色
     * @return
     */
    List getFruits() {
        return (List) fruits.clone();
    }
}

【Caretaker】

package com.atguigu.memento.Sample;
import com.atguigu.memento.Sample.game.Gamer;
import com.atguigu.memento.Sample.game.Memento;
public class Main {
    public static void main(String[] args) {
        // 最初的所持金钱数为100
        Gamer gamer = new Gamer(100);
        // 保存最初的状态
        Memento memento = gamer.createMemento();
        for (int i = 0; i < 10; i++) {
            // 显示掷骰子的次数
            System.out.println("==== " + i);
            // 显示主人公现在的状态
            System.out.println("当前状态:" + gamer);
            // 进行游戏
            gamer.bet();
            System.out.println("所持金钱为" + gamer.getMoney() + "元。");
            // 决定如何处理Memento
            if (gamer.getMoney() > memento.getMoney()) {
                System.out.println("    (所持金钱增加了许多,因此保存游戏当前的状态)");
                memento = gamer.createMemento();
            } else if (gamer.getMoney() < memento.getMoney() / 2) {
                System.out.println("    (所持金钱减少了许多,因此将游戏恢复至以前的状态)");
                gamer.restoreMemento(memento);
            }
            // 等待一段时间
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println("");
        }
    }
}

【运行】

==== 0
当前状态:[money = 100, fruits = []]
什么都没有发生。
所持金钱为100元。
==== 1
当前状态:[money = 100, fruits = []]
所持金钱增加了。
所持金钱为200元。
    (所持金钱增加了许多,因此保存游戏当前的状态)
==== 2
当前状态:[money = 200, fruits = []]
什么都没有发生。
所持金钱为200元。
==== 3
当前状态:[money = 200, fruits = []]
什么都没有发生。
所持金钱为200元。
==== 4
当前状态:[money = 200, fruits = []]
什么都没有发生。
所持金钱为200元。
==== 5
当前状态:[money = 200, fruits = []]
什么都没有发生。
所持金钱为200元。
==== 6
当前状态:[money = 200, fruits = []]
什么都没有发生。
所持金钱为200元。
==== 7
当前状态:[money = 200, fruits = []]
什么都没有发生。
所持金钱为200元。
==== 8
当前状态:[money = 200, fruits = []]
所持金钱减半了。
所持金钱为100元。
==== 9
当前状态:[money = 100, fruits = []]
所持金钱增加了。
所持金钱为200元。
Process finished with exit code 0

拓展

使用序列化(Serialization)功能来将Memento类的实例保存为文件。请修改示例程序以实现下列功能。

  • 在应用程序启动时,如果发现不存在game.dat文件时,以所持金钱数目为100开始游戏;如果发现 game.dat 已经存在,则以文件中所保存的状态开始游戏
  • 当所持金钱大量增加后,将Memento类的实例保存到game.dat文件中
  1. 将Memento继承Serializable接口来实现序列化操作,除此之外,不需要进行其他修改
public class Memento implements Serializable {}
  1. 想要扩展实例保存到文件的功能,只需要修改Caretaker
package com.atguigu.memento.A4;
import com.atguigu.memento.A4.game.Gamer;
import com.atguigu.memento.A4.game.Memento;
import java.io.*;
public class Main {
    /**
     * 数据保存的文件名
     */
    public static final String SAVE_FILE_NAME = "game.dat";
    public static void main(String[] args) {
        // 最初的所持金钱数为100
        Gamer gamer = new Gamer(100);
        // 从文件中读取起始状态
        Memento memento = loadMemento();
        if (memento != null) {
            System.out.println("读取上次保存存档开始游戏。");
            gamer.restoreMemento(memento);
        } else {
            System.out.println("新游戏。");
            memento = gamer.createMemento();
        }
        for (int i = 0; i < 100; i++) {
            // 显示次数
            System.out.println("==== " + i);
            // 显示当前主人公的状态
            System.out.println("当前状态:" + gamer);
            // 进行游戏
            gamer.bet();   
            System.out.println("所持金钱为" + gamer.getMoney() + "元。");
            // 决定如何处理Memento
            if (gamer.getMoney() > memento.getMoney()) {
                System.out.println("    (所持金钱增加了许多,因此保存游戏当前的状态)");
                memento = gamer.createMemento();
                // 将实例保存至文件中
                saveMemento(memento);
            } else if (gamer.getMoney() < memento.getMoney() / 2) {
                System.out.println("    (所持金钱减少了许多,因此将游戏恢复至以前的状态)");
                gamer.restoreMemento(memento);
            }
            // 等待一段时间
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println("");
        }
    }
    /**
     * 保存实例到文件中
     * @param memento
     */
    public static void saveMemento(Memento memento) {   
        try {
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream(SAVE_FILE_NAME));
            out.writeObject(memento);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 从文件中读取实例
     * @return
     */
    public static Memento loadMemento() {               
        Memento memento = null;
        try {
            ObjectInput in = new ObjectInputStream(new FileInputStream(SAVE_FILE_NAME));
            memento = (Memento)in.readObject();
            in.close();
        } catch (FileNotFoundException e) {
            System.out.println(e.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return memento;
    }
}

总结

【优点】

  • 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回退到某个历史的状态
  • 实现了信息的封装,使用户不需要关心状态的保存细节

【缺点】

  • 如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存,这个需要注意。为了节约内存,备忘录模式可以和原型模式配合使用

【适用应用场景】

  • 打游戏时的存档
  • Windows 里的ctrl+z
  • IE 中的后退
  • 数据库的事务管理

文章说明

  • 本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。
  • 本人还同步阅读《图解设计模式》书籍(图解设计模式/(日)结城浩著;杨文轩译–北京:人民邮电出版社,2017.1),进而综合两者的内容,让知识点更加全面
目录
相关文章
|
5天前
|
存储 监控 Java
JAVA线程池有哪些队列? 以及它们的适用场景案例
不同的线程池队列有着各自的特点和适用场景,在实际使用线程池时,需要根据具体的业务需求、系统资源状况以及对任务执行顺序、响应时间等方面的要求,合理选择相应的队列来构建线程池,以实现高效的任务处理。
81 12
|
21天前
|
监控 Java API
探索Java NIO:究竟在哪些领域能大显身手?揭秘原理、应用场景与官方示例代码
Java NIO(New IO)自Java SE 1.4引入,提供比传统IO更高效、灵活的操作,支持非阻塞IO和选择器特性,适用于高并发、高吞吐量场景。NIO的核心概念包括通道(Channel)、缓冲区(Buffer)和选择器(Selector),能实现多路复用和异步操作。其应用场景涵盖网络通信、文件操作、进程间通信及数据库操作等。NIO的优势在于提高并发性和性能,简化编程;但学习成本较高,且与传统IO存在不兼容性。尽管如此,NIO在构建高性能框架如Netty、Mina和Jetty中仍广泛应用。
30 3
|
21天前
|
安全 算法 Java
Java CAS原理和应用场景大揭秘:你掌握了吗?
CAS(Compare and Swap)是一种乐观锁机制,通过硬件指令实现原子操作,确保多线程环境下对共享变量的安全访问。它避免了传统互斥锁的性能开销和线程阻塞问题。CAS操作包含三个步骤:获取期望值、比较当前值与期望值是否相等、若相等则更新为新值。CAS广泛应用于高并发场景,如数据库事务、分布式锁、无锁数据结构等,但需注意ABA问题。Java中常用`java.util.concurrent.atomic`包下的类支持CAS操作。
56 2
|
2月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
2月前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
2月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
46 4
|
2月前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
|
14天前
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
|
2月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
4月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。