zencart 网站建设,综合网站推广,新闻发稿软文推广,西安微信平台网站建设玄子Share 设计模式 GOF 全23种 七大设计原则 前言#xff1a; 此文主要内容为 面向对象七大设计原则#xff08;OOD Principle#xff09;GOF#xff08;Gang Of Four#xff09;23种设计模式拓展的两个设计模式 简单工厂模式#xff08;Simple Factory Pattern#x…
玄子Share 设计模式 GOF 全23种 七大设计原则 前言 此文主要内容为 面向对象七大设计原则OOD PrincipleGOFGang Of Four23种设计模式拓展的两个设计模式 简单工厂模式Simple Factory Pattern空对象模式Null Object Pattern以及工厂模式与策略模式Factory And Strategy Pattern之间的区别两个设计模式较为相似细节上需要分清 每个设计模式都分为了八步介绍 先对设计模式进行简单介绍尽量一句话概述方便记忆再以现实生活中的场景举例抛出问题使用对应的设计模式解决问题提供了方便理解的类关系图然后指出适用于当前设计模式的场景当前设计模式编码时的易错点当前设计模式的优缺点最后再次对当前设计模式进行总结 使用代码案例时可复制整个代码块先粘贴至一个类中再拆分 如有疑问添加文章封面联系方式 目录 文章目录 玄子Share 设计模式 GOF 全23种 七大设计原则目录[toc] 设计模式分类 GOFGang Of Four创建型模式Creational Patterns结构型模式Structural Patterns行为型模式Behavioral Patterns 面向对象设计原则OOD Principle单一职责原则SRP开闭原则OCP里氏替换原则LSP接口隔离原则ISP依赖倒置原则DIP迪米特法则LOD合成复用原则CRP 创建型模式 (Creational Patterns)工厂方法模式Factory Method Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 抽象工厂模式Abstract Factory Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 单例模式Singleton Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 原型模式Prototype Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 建造者模式Builder Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 结构型模式 (Structural Patterns)适配器模式Adapter Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 桥接模式Bridge Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 组合模式Composite Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 装饰模式Decorator Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 外观模式Facade Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 享元模式Flyweight Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 代理模式Proxy Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 行为型模式 (Behavioral Patterns)责任链模式Chain of Responsibility Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 命令模式Command Pattern1. 简单介绍1. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 解释器模式Interpreter Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 迭代器模式Iterator Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 中介者模式Mediator Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 备忘录模式Memento Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 观察者模式Observer Pattern1. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 状态模式State Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 策略模式Strategy Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 模板方法模式Template Method Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 访问者模式Visitor Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 必要性拓展Necessity Expansion简单工厂模式Simple Factory Pattern1. 简单介绍2. 实际问题3. 实现方式4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 空对象模式Null Object Pattern1. 简单介绍2. 实际问题3. 解决方案4. 类关系图5. 应用场景6. 易错点7. 优缺点8. 总结 工厂模式与策略模式Factory And Strategy Pattern1. 工厂模式Factory Pattern2. 策略模式Strategy Pattern3. 区别总结Difference Summary 设计模式拓展Design Mode Expansion
设计模式分类 GOFGang Of Four
GOFGang Of Four是四位计算机科学家Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides在1994年出版的书籍《设计模式可复用面向对象软件的基础》中提出的一种设计模式分类和解决方案。该书介绍了23种常用的设计模式分为创建型、结构型和行为型三大类。这本书的社会认可度非常高被公认为设计模式领域的经典之作。
影响深远GOF的设计模式成为了软件工程领域的经典之一对于软件设计和架构具有广泛的应用。许多软件开发人员和团队都在日常工作中使用这些模式来解决常见的设计问题。经典的设计原则GOF的设计模式不仅提供了具体的解决方案还强调了面向对象设计的一些重要原则如封装、继承、多态和接口分离等。共同的设计术语GOF提出的模式在软件开发社区中创建了共同的设计术语和设计思维方式使得开发人员之间更容易进行沟通和理解。可复用性和可维护性通过应用这些设计模式开发人员可以更好地设计出具有可复用性和可维护性的软件系统降低了代码的耦合性。
GOF的设计模式在软件开发领域得到了广泛的认可和应用成为了许多软件开发人员必备的知识和工具之一。它为软件设计和架构提供了有力的指导帮助开发人员构建高质量、可扩展的软件系统。
创建型模式Creational Patterns
序号中文名称英文名称所用设计原则1工厂方法模式Factory Method PatternSRP、OCP、LSP、DIP2抽象工厂模式Abstract Factory PatternSRP、OCP、LSP、DIP3单例模式Singleton Pattern无直接关联设计原则4原型模式Prototype PatternSRP、OCP、LSP、DIP5建造者模式Builder PatternSRP、OCP、LSP、DIP
结构型模式Structural Patterns
序号中文名称英文名称所用设计原则6适配器模式Adapter PatternSRP、OCP、LSP、ISP、DIP7桥接模式Bridge PatternSRP、OCP、LSP、ISP、DIP8组合模式Composite PatternSRP、OCP、LSP、ISP、DIP9装饰模式Decorator PatternSRP、OCP、LSP、ISP、DIP10外观模式Facade PatternSRP、OCP、LSP、ISP、DIP11享元模式Flyweight PatternSRP、OCP、LSP、ISP、DIP12代理模式Proxy PatternSRP、OCP、LSP、ISP、DIP
行为型模式Behavioral Patterns
序号中文名称英文名称所用设计原则13责任链模式Chain of Responsibility PatternSRP、OCP、LSP、ISP、DIP14命令模式Command PatternSRP、OCP、LSP、ISP、DIP15解释器模式Interpreter PatternSRP、OCP、LSP、ISP、DIP16迭代器模式Iterator PatternSRP、OCP、LSP、ISP、DIP17中介者模式Mediator PatternSRP、OCP、LSP、ISP、DIP18备忘录模式Memento PatternSRP、OCP、LSP、ISP、DIP19观察者模式Observer PatternSRP、OCP、LSP、ISP、DIP20状态模式State PatternSRP、OCP、LSP、ISP、DIP21策略模式Strategy PatternSRP、OCP、LSP、ISP、DIP22模板方法模式Template Method PatternSRP、OCP、LSP、ISP、DIP23访问者模式Visitor PatternSRP、OCP、LSP、ISP、DIP 面向对象设计原则OOD Principle
面向对象设计原则OODPObject-Oriented Design Principle
面向对象设计原则是一组指导性准则是设计模式的基础用于帮助软件开发人员设计和构建高质量、灵活、可维护和可扩展的面向对象软件系统。遵循这些原则有助于提高代码的质量减少重构的需求避免常见的设计问题并提高软件系统的可靠性和可重用性帮助我们构建出更好的软件。
单一职责原则SRP
单一职责原则SRPSingle Responsibility Principle
每个类或模块应该有且只有一个单一的责任。换句话说一个类应该只负责完成一个明确定义的功能。这样做可以降低类的复杂性提高类的可维护性和可重用性。
开闭原则OCP
开闭原则OCPOpen/Closed Principle
软件实体类、模块、函数等应该对扩展开放对修改关闭。这意味着当需要添加新功能时应该通过扩展现有代码来实现而不是修改现有代码。这样可以保持现有功能的稳定性并降低引入新功能时引入错误的风险。
里氏替换原则LSP
里氏替换原则LSPLiskov Substitution Principle
子类应该能够替换其父类并出现在任何使用父类的地方而不会影响程序的正确性。这就要求子类必须保持父类的行为即子类不能修改父类的行为。
接口隔离原则ISP
接口隔离原则ISP Interface Segregation Principle
不应该强迫客户端依赖于它们不使用的接口。接口应该被细化只包含客户端需要的方法这样可以降低类之间的耦合度提高系统的灵活性和可维护性。
依赖倒置原则DIP
依赖倒置原则DIPDependency Inversion Principle
高层模块不应该依赖于低层模块而是应该依赖于抽象。抽象不应该依赖于具体实现而是具体实现应该依赖于抽象。这样可以降低模块之间的耦合度提高代码的可测试性和可扩展性。
迪米特法则LOD
迪米特法则LoDLaw Of Demeter
也称为最少知识原则。一个对象应该对其他对象有尽可能少的了解只与直接的朋友进行交互。这样可以降低类之间的耦合度使系统更加灵活和易于维护。
合成复用原则CRP
合成复用原则CRPComposite Reuse Principle
尽量使用组合/聚合的方式而不是继承关系达到软件复用的目的是 has-a 关系而不是通过继承。该原则促使开发者在设计中更多地考虑对象之间的组合关系以达到模块化、灵活性和可维护性的目标。 创建型模式 (Creational Patterns)
创建型模式是设计模式中的一类主要关注如何创建对象以及对象的实例化过程。它们提供了一种灵活、可复用的方式来创建对象同时隐藏了对象创建的细节从而降低了系统的耦合性。
这些创建型模式各自适用于不同的场景可以根据具体需求来选择合适的设计模式来实现对象的创建和初始化。它们的共同目标是降低对象的创建和使用之间的耦合提供更加灵活和可扩展的代码结构。 工厂方法模式Factory Method Pattern
在学习工厂方法模式之前建议先学习文章最后一章《必要拓展》中的简单工厂模式Simple Factory Pattern
1. 简单介绍
工厂方法模式Factory Method Pattern定义一个创建对象的接口但由子类决定具体实例化哪个类。客户端只需要知道工厂接口而不关心具体的产品类。
2. 实际问题
假设你是一家汽车制造公司你有多个型号的汽车需要生产每种型号的汽车有不同的配置和特性。你需要一个灵活的方式来生产不同型号的汽车并且在将来能够轻松添加新的汽车型号。
3. 解决方案
定义一个产品接口规范产品的行为。创建一个工厂接口包含一个工厂方法用于创建产品对象。对每个具体产品创建一个具体产品类实现产品接口。对每个具体产品创建一个具体工厂类实现工厂接口负责创建具体产品的实例。
// 产品接口汽车
interface Car {void assemble();
}// 具体产品SUV 汽车
class SUVCar implements Car {Overridepublic void assemble() {System.out.println(组装SUV汽车);}
}// 具体产品轿车
class SedanCar implements Car {Overridepublic void assemble() {System.out.println(组装轿车);}
}// 工厂接口汽车工厂
interface CarFactory {Car createCar();
}// 具体工厂SUV 汽车工厂
class SUVCarFactory implements CarFactory {Overridepublic Car createCar() {return new SUVCar();}
}// 具体工厂轿车工厂
class SedanCarFactory implements CarFactory {Overridepublic Car createCar() {return new SedanCar();}
}// 调用代码
public class XZ {public static void main(String[] args) {System.out.println(SUV);Car suvCar new SUVCarFactory().createCar();suvCar.assemble();System.out.println(Sedan);Car sedanCar new SedanCarFactory().createCar();sedanCar.assemble();}
}4. 类关系图 5. 应用场景
当一个类无法预先知道它需要创建的对象的确切类时使用工厂方法可以延迟对象的实例化使得具体的实例化由子类来决定。当需要在运行时动态地选择创建某个类的对象时工厂方法提供了一种灵活的解决方案。
6. 易错点
忘记实现产品接口每个具体产品都必须实现产品接口否则无法通过工厂方法创建产品对象。忘记实现工厂接口每个具体工厂都必须实现工厂接口以提供工厂方法来创建产品对象。
7. 优缺点
优点
通过工厂方法将产品的创建与使用解耦客户端不需要知道具体产品的类名只需要通过工厂接口来创建对象降低了耦合度。具体产品的新增和变更对客户端代码没有影响只需要新增或修改相应的具体工厂类即可。
缺点
每新增一个具体产品都需要新增一个相应的具体工厂类导致类的个数增加增加了系统的复杂性。
8. 总结
工厂方法模式是一种创建型设计模式通过将产品的创建与使用解耦让子类决定实例化哪个类。这样可以提高代码的灵活性和可扩展性使得系统的演化和维护更加容易。虽然增加了类的个数但对于复杂系统的开发来说这是值得的权衡。在需要动态地选择创建对象或者有多个类似产品等级结构的情况下工厂方法模式是一个很好的选择。 抽象工厂模式Abstract Factory Pattern
1. 简单介绍
抽象工厂模式Abstract Factory Pattern提供一个创建一系列相关或相互依赖对象的接口而无需指定它们具体的类。抽象工厂可以创建多个不同类型的产品。
2. 实际问题
假设你是一家家具制造公司你有多种类型的家具如沙发、床、桌子等每种类型的家具有不同的风格和材料。你需要一种灵活的方式来生产不同类型和风格的家具并且在将来能够轻松添加新的家具类型和风格。
3. 解决方案
// 产品接口沙发
interface Sofa {void sitOn();
}// 产品接口床
interface Bed {void sleepOn();
}// 具体产品现代风格沙发
class ModernSofa implements Sofa {Overridepublic void sitOn() {System.out.println(坐在现代风格的沙发上);}
}// 具体产品现代风格床
class ModernBed implements Bed {Overridepublic void sleepOn() {System.out.println(睡在现代风格的床上);}
}// 具体产品古典风格沙发
class ClassicalSofa implements Sofa {Overridepublic void sitOn() {System.out.println(坐在古典风格的沙发上);}
}// 具体产品古典风格床
class ClassicalBed implements Bed {Overridepublic void sleepOn() {System.out.println(睡在古典风格的床上);}
}// 抽象工厂接口家具工厂
interface FurnitureFactory {Sofa createSofa();Bed createBed();
}// 具体工厂现代风格家具工厂
class ModernFurnitureFactory implements FurnitureFactory {Overridepublic Sofa createSofa() {return new ModernSofa();}Overridepublic Bed createBed() {return new ModernBed();}
}// 具体工厂古典风格家具工厂
class ClassicalFurnitureFactory implements FurnitureFactory {Overridepublic Sofa createSofa() {return new ClassicalSofa();}Overridepublic Bed createBed() {return new ClassicalBed();}
}// 调用代码
public class XZ {public static void main(String[] args) {System.out.println(现代家具);ModernFurnitureFactory modernFurnitureFactory new ModernFurnitureFactory();Bed modernBed modernFurnitureFactory.createBed();modernBed.sleepOn();Sofa modernSofa modernFurnitureFactory.createSofa();modernSofa.sitOn();System.out.println(古典家具);ClassicalFurnitureFactory classicalFurnitureFactory new ClassicalFurnitureFactory();Bed classicaBed classicalFurnitureFactory.createBed();classicaBed.sleepOn();Sofa classicaSofa classicalFurnitureFactory.createSofa();classicaSofa.sitOn();}
}4. 类关系图 5. 应用场景
当需要创建一组相关或相互依赖的对象时可以使用抽象工厂模式。例如创建不同风格的家具或者创建不同主题的界面元素等。当希望系统在未来能够支持新的产品种类或产品族而不需要修改现有代码时抽象工厂模式提供了一种扩展的解决方案。
6. 易错点
在添加新的产品族时需要修改抽象工厂接口及其所有子类可能导致较大的改动。在添加新的产品等级结构时需要修改抽象工厂接口及其所有子类可能导致较大的改动。
7. 优缺点
优点
将一组相关的产品封装在一起客户端使用抽象接口来创建产品不需要关心具体的实现细节降低了客户端和具体产品类之间的耦合。可以轻松替换不同的工厂类来创建不同的产品族增加新的产品族也方便符合开闭原则。
缺点
增加新的产品族或产品等级结构时需要修改抽象工厂接口及其所有子类可能导致较大的改动。当产品族和产品等级结构过于复杂时抽象工厂模式的类的数量可能会增加导致系统复杂性增加。
8. 总结
抽象工厂模式是一种创建型设计模式通过提供一个接口来创建一组相关或相互依赖的对象将一系列产品封装在一起使得客户端不需要知道具体产品的类名只需使用抽象接口即可。抽象工厂模式适用于创建一组相关的产品且希望系统能够轻松支持新的产品族或产品等级结构的场景。在使用抽象工厂模式时需要注意在添加新的产品族或产品等级结构时可能需要修改较多的代码。 单例模式Singleton Pattern
1. 简单介绍
单例模式Singleton Pattern确保一个类只有一个实例并提供一个全局访问点。这样可以控制对象的创建和访问通常用于管理共享资源或全局配置。
2. 实际问题
在现实世界中我们可能会遇到这样的问题希望某个类在整个应用程序中只能拥有一个实例不论在何处访问该类始终获取到相同的唯一实例。
3. 解决方案
静态内部类
静态内部类单例模式是一种创建单例对象的方法它通过使用静态内部类来实现懒加载和线程安全。
// 静态内部类单例
public class StaticInnerClassSingleton {private static class StaticInnerClass {private static final StaticInnerClassSingleton staticInnerClassSingleton new StaticInnerClassSingleton();}public static StaticInnerClassSingleton getInstance() {return StaticInnerClass.staticInnerClassSingleton;}
}// 调用代码
public class XZ {public static void main(String[] args) {// 获取懒汉式单例实例StaticInnerClassSingleton instance1 StaticInnerClassSingleton.getInstance();StaticInnerClassSingleton instance2 StaticInnerClassSingleton.getInstance();// 验证是否为同一实例System.out.println(instance1 instance2);// Output: true}
}懒汉式单例
懒汉式是指在首次使用时才创建实例。解决方案为在类内部定义一个私有静态变量作为该类的唯一实例并提供一个公共静态方法来获取该实例。
// 懒汉式单例
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}// 私有构造方法防止其他类通过 new 创建实例public static synchronized LazySingleton getInstance() {if (instance null) {instance new LazySingleton();}return instance;}
}// 调用代码
public class XZ {public static void main(String[] args) {// 获取懒汉式单例实例LazySingleton instance1 LazySingleton.getInstance();LazySingleton instance2 LazySingleton.getInstance();// 验证是否为同一实例System.out.println(instance1 instance2); // Output: true}
}饿汉式单例
饿汉式是指在类加载时就创建实例。解决方案为在类定义时直接创建一个私有静态实例并提供一个公共静态方法来获取该实例。
// 饿汉式单例
public class EagerSingleton {private static final EagerSingleton instance new EagerSingleton();private EagerSingleton() {}// 私有构造方法防止其他类通过 new 创建实例public static EagerSingleton getInstance() {return instance;}
}// 调用代码
public class XZ {public static void main(String[] args) {// 获取饿汉式单例实例EagerSingleton instance1 EagerSingleton.getInstance();EagerSingleton instance2 EagerSingleton.getInstance();// 验证是否为同一实例System.out.println(instance1 instance2); // Output: true}
}双重校验锁单例
双重校验锁单例是一种在懒汉式基础上进行改进的解决方案旨在减少不必要的同步开销。
// 双重校验锁单例
public class DoubleCheckedSingleton {private volatile static DoubleCheckedSingleton instance;private DoubleCheckedSingleton() {}// 私有构造方法防止其他类通过 new 创建实例public static DoubleCheckedSingleton getInstance() {if (instance null) {synchronized (DoubleCheckedSingleton.class) {if (instance null) {instance new DoubleCheckedSingleton();}}}return instance;}
}// 调用代码
public class XZ {public static void main(String[] args) {// 获取双重校验锁单例实例DoubleCheckedSingleton instance1 DoubleCheckedSingleton.getInstance();DoubleCheckedSingleton instance2 DoubleCheckedSingleton.getInstance();// 验证是否为同一实例System.out.println(instance1 instance2);// Output: true}
}枚举单例
枚举单例是一种简洁且线程安全的单例模式解决方案。在Java中枚举类型是天然的单例保证在任何情况下都只有一个实例。
// 枚举单例
public enum EnumSingleton {INSTANCE;public static EnumSingleton getInstance() {return INSTANCE;}
}// 调用代码
public class XZ {public static void main(String[] args) {// 获取枚举单例实例EnumSingleton instance1 EnumSingleton.getInstance();EnumSingleton instance2 EnumSingleton.getInstance();// 验证是否为同一实例System.out.println(instance1 instance2);// Output: true}
}在每个示例中我们都通过相应的静态方法获取单例实例并通过比较引用地址验证是否为同一实例。由于单例模式保证在整个应用程序中只有一个实例所以输出结果都应该是true。 4. 类关系图 5. 应用场景
需要在整个应用程序中共享某个资源例如配置信息、数据库连接等。控制资源的并发访问避免资源冲突。
6. 易错点
线程安全问题懒汉式和双重校验锁单例在多线程环境下可能会创建多个实例需要采取同步措施保证线程安全但同步会影响性能。反序列化问题如果单例类实现了Serializable接口当对象被反序列化时可能会创建新的实例破坏单例特性需要通过readResolve()方法解决。
7. 优缺点
静态内部类单例模式 优点 单例对象只有在第一次使用时才会被创建提高了性能和资源利用率。静态内部类的加载过程由类加载器保证了线程安全无需额外的同步措施。实现简单代码清晰不依赖复杂的同步机制。 缺点 静态内部类单例模式无法传递参数给单例类的构造函数因此在一些特殊情况下可能不适用。
懒汉式单例模式 优点 实现懒加载只有在实例需要时才会创建。简单易懂。 缺点 线程安全需要额外考虑可能会影响性能。反序列化可能会破坏单例特性。
饿汉式单例模式 优点 实现简单不需要考虑线程安全问题。线程安全可以直接用于多线程环境。 缺点 不支持懒加载可能导致资源浪费。
双重校验锁单例模式 优点 实现懒加载只有在实例需要时才会创建。在多线程环境下保持了较好的性能。 缺点 实现相对复杂容易出错。JDK 1.5之前的版本中可能存在双重检查锁失效的问题。
枚举单例模式 优点 简洁且线程安全天然保证只有一个实例。支持其他方法和属性的定义。 缺点 不能实现懒加载实例在类加载时就被创建。
8. 总结
静态内部类单例模式通过静态内部类实现了懒加载和线程安全代码简洁清晰。适合大多数情况下的单例需求。饿汉式单例模式在类加载时就创建实例天生线程安全但可能浪费资源因为不管是否使用都会创建实例。懒汉式单例模式在第一次使用时才创建实例节省了资源但需要考虑线程安全问题通常需要加锁来保证线程安全。双重校验锁单例模式结合了饿汉式和懒汉式的优点懒加载且线程安全。但实现相对复杂需要考虑指令重排问题。枚举单例模式使用枚举类型来实现单例天生线程安全且防止反射和序列化攻击。简单、安全但无法懒加载。
选择哪种单例模式应该根据具体需求来决定。静态内部类单例模式通常是一个很好的选择因为它兼具了懒加载和线程安全的优点而且实现简单。如果需要更高级的特性如防止反射攻击可以考虑使用枚举单例模式。 原型模式Prototype Pattern
1. 简单介绍
原型模式Prototype Pattern通过复制现有对象来创建新的对象避免了使用常规构造函数来创建对象从而提高性能和灵活性。
2. 实际问题
在现实世界中我们可能会遇到这样的问题希望创建一个对象的副本并且可以根据原对象进行快速的复制和修改。
3. 解决方案
原型模式是一种创建型设计模式它通过复制现有对象来创建新对象。Java中可以通过实现Cloneable接口和重写clone()方法来实现原型模式。
浅克隆
// 原型对象类
public class Prototype implements Cloneable {private String data;public Prototype(String data) {this.data data;}// 重写clone方法实现浅拷贝Overridepublic Prototype clone() throws CloneNotSupportedException {return (Prototype) super.clone();}public String getData() {return data;}public void setData(String data) {this.data data;}
}// 调用代码的类
public class XZ {public static void main(String[] args) throws CloneNotSupportedException {Date date new Date();// 创建原型对象Prototype originalPrototype new Prototype(玄子, date);// 克隆原型对象Prototype clonedPrototype originalPrototype.clone();System.out.println(源对象 originalPrototype.hashCode() , originalPrototype.getName() , originalPrototype.getBirthday());System.out.println(克隆对象 clonedPrototype.hashCode() , clonedPrototype.getName() , clonedPrototype.getBirthday());System.out.println();date.setTime(22222222);System.out.println(源对象 originalPrototype.hashCode() , originalPrototype.getName() , originalPrototype.getBirthday());System.out.println(克隆对象 clonedPrototype.hashCode() , clonedPrototype.getName() , clonedPrototype.getBirthday());// 虽然克隆出来的是两个内存地址的对象// 但修改数据后源对象与克隆对象的数据都发生了改变// 数据引用的是同一内存地址}/*源对象990368553,玄子,Sun Sep 24 02:50:52 CST 2023克隆对象396873410,玄子,Sun Sep 24 02:50:52 CST 2023源对象990368553,玄子,Thu Jan 01 14:10:22 CST 1970克隆对象396873410,玄子,Thu Jan 01 14:10:22 CST 1970*/
}克隆属性实现深克隆
// 重写clone方法与属性实现深拷贝
Override
public Prototype clone() throws CloneNotSupportedException {Prototype clone (Prototype) super.clone();clone.birthday (Date) this.birthday.clone();return clone;
}
// 实现深克隆仅需要在源对象的 clone() 方法内对属性进行单独克隆
/*源对象990368553,玄子,Sun Sep 24 02:50:52 CST 2023克隆对象396873410,玄子,Sun Sep 24 02:50:52 CST 2023源对象990368553,玄子,Thu Jan 01 14:10:22 CST 1970克隆对象396873410,玄子,Sun Sep 24 03:00:40 CST 2023*/使用反序列化实现深克隆
// 原型对象类实现 Serializable 接口
public class Prototype implements Serializable {private String name;private Date birthday;public Prototype(String name, Date birthday) {this.name name;this.birthday birthday;}// 使用序列化和反序列化实现深拷贝public Prototype deepClone() throws IOException, ClassNotFoundException {ByteArrayOutputStream bos new ByteArrayOutputStream();ObjectOutputStream oos new ObjectOutputStream(bos);// 序列化当前对象oos.writeObject(this);ByteArrayInputStream bis new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois new ObjectInputStream(bis);// 反序列化为新对象return (Prototype) ois.readObject();}public String getName() {return name;}public void setName(String name) {this.name name;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday birthday;}
}// 调用代码的类
public class XZ {public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {Date date new Date();// 创建原型对象Prototype originalPrototype new Prototype(玄子, date);// 克隆原型对象Prototype clonedPrototype originalPrototype.deepClone();System.out.println(源对象 originalPrototype.hashCode() , originalPrototype.getName() , originalPrototype.getBirthday());System.out.println(克隆对象 clonedPrototype.hashCode() , clonedPrototype.getName() , clonedPrototype.getBirthday());System.out.println();date.setTime(22222222);System.out.println(源对象 originalPrototype.hashCode() , originalPrototype.getName() , originalPrototype.getBirthday());System.out.println(克隆对象 clonedPrototype.hashCode() , clonedPrototype.getName() , clonedPrototype.getBirthday());}/*源对象990368553,玄子,Sun Sep 24 02:50:52 CST 2023克隆对象396873410,玄子,Sun Sep 24 02:50:52 CST 2023源对象990368553,玄子,Thu Jan 01 14:10:22 CST 1970克隆对象396873410,玄子,Thu Jan 01 14:10:22 CST 1970*/
}4. 类关系图 5. 应用场景
需要创建复杂对象但创建过程较为耗时。需要创建大量相似对象复制现有对象比重新创建更高效。
6. 易错点
浅拷贝问题默认情况下clone()方法执行的是浅拷贝即只复制基本类型的字段和引用类型的地址而不复制引用类型对象本身。如果对象中包含引用类型字段需要注意处理深拷贝问题。
7. 优缺点
优点
提高对象的创建效率避免重复执行初始化操作。方便快速创建和修改对象副本。
缺点
如果对象的复制过程较为复杂可能需要实现深拷贝。在处理引用类型字段时需要特别注意避免共享引用对象导致意外修改。
8. 总结
原型模式是一种创建型设计模式通过复制现有对象来创建新对象。在Java中可以通过实现Cloneable接口和重写clone()方法来实现原型模式。原型模式适用于需要创建复杂对象或大量相似对象的场景可以提高对象的创建效率并方便快速创建和修改对象副本。需要注意处理引用类型字段时的浅拷贝问题并根据具体情况考虑是否需要实现深拷贝。 建造者模式Builder Pattern
1. 简单介绍
建造者模式Builder Pattern将一个复杂对象的构建过程与其表示分离使得同样的构建过程可以创建不同的表示。
2. 实际问题
在现实世界中我们可能会遇到这样的问题希望构建一个复杂的对象该对象有多个可选属性并且在创建过程中可以灵活组合这些属性。
3. 解决方案
建造者模式是一种创建型设计模式它通过将对象的构建过程和表示分离使得同样的构建过程可以创建不同的表示。建造者模式通常包含一个Builder接口和一个ConcreteBuilder实现类以及一个Director类来指导构建过程。
建造者模式
// 建造者接口
public interface Builder {void buildPart1();void buildPart2();void buildPart3();Product getResult();
}// 具体建造者
public class ConcreteBuilder implements Builder {private final Product product new Product();public void buildPart1() {product.setPart1(Part1);}public void buildPart2() {product.setPart2(Part2);}public void buildPart3() {product.setPart3(Part3);}public Product getResult() {return product;}
}// 产品类
public class Product {private String part1;private String part2;private String part3;public String getPart1() {return part1;}public void setPart1(String part1) {this.part1 part1;}public String getPart2() {return part2;}public void setPart2(String part2) {this.part2 part2;}public String getPart3() {return part3;}public void setPart3(String part3) {this.part3 part3;}Overridepublic String toString() {return Product{ part1 part1 \ , part2 part2 \ , part3 part3 \ };}}// 指导者类
public class Director {public void construct(Builder builder) {builder.buildPart1();builder.buildPart2();builder.buildPart3();}
}// 调用代码
public class XZ {public static void main(String[] args) {// 创建指导者和建造者对象Director director new Director();Builder builder new ConcreteBuilder();// 指导建造过程并获取产品对象director.construct(builder);Product product builder.getResult();// 输出产品信息产品信息顺序固定System.out.println(product);// Output: Product{part1Part1, part2Part2, part3Part3}}
}建造者模式无指挥Director
// 建造者接口
public interface Builder {Builder buildPart1(String part);Builder buildPart2(String part);Builder buildPart3(String part);Product getResult();
}// 具体建造者
public class ConcreteBuilder implements Builder {private final Product product new Product();public Builder buildPart1(String part) {product.setPart1(part);return this;}public Builder buildPart2(String part) {product.setPart2(part);return this;}public Builder buildPart3(String part) {product.setPart3(part);return this;}public Product getResult() {return product;}
}// 产品类
public class Product {private String part1 part1;private String part2 part1;private String part3 part1;public String getPart1() {return part1;}public void setPart1(String part1) {this.part1 part1;}public String getPart2() {return part2;}public void setPart2(String part2) {this.part2 part2;}public String getPart3() {return part3;}public void setPart3(String part3) {this.part3 part3;}Overridepublic String toString() {return Product{ part1 part1 \ , part2 part2 \ , part3 part3 \ };}}// 调用代码
public class XZ {public static void main(String[] args) {// 创建指导者和建造者对象ConcreteBuilder concreteBuilder new ConcreteBuilder();Product product concreteBuilder.getResult();// 输出产品信息System.out.println(product);// Output: Product{part1Part1, part2Part2, part3Part3}System.out.println();// 创建指导者和建造者对象ConcreteBuilder concreteBuilder2 new ConcreteBuilder();// 链式编程在原来的基础上可自由组合若不组合则默认Product product2 concreteBuilder2.buildPart1(part2).buildPart2(part1).buildPart3(part3).getResult();// 输出产品信息产品信息顺序可自由搭配System.out.print(product2);// Output: Product{part1part2, part2part1, part3part3}}
}
4. 类关系图 5. 应用场景
需要创建复杂对象且对象的构建过程相对稳定但表示可以灵活组合的场景。当一个对象有多个可选属性且属性之间有依赖关系时可以使用建造者模式进行构建。
6. 易错点
需要根据实际需求定义建造者接口和具体建造者类确保建造过程的正确性和灵活性。在指导者类中指导建造过程确保正确的建造顺序和步骤。
7. 优缺点
优点
将对象的构建过程和表示分离使得构建过程可以创建不同的表示提高了构建过程的灵活性。可以隐藏产品的内部结构使得客户端只关注产品的高层接口。
缺点
需要定义多个类增加了代码复杂性。不适用于只有少量可选属性的对象过度使用建造者模式可能会导致代码冗余。
8. 总结
建造者模式是一种创建型设计模式它通过将对象的构建过程和表示分离使得同样的构建过程可以创建不同的表示。在Java中可以通过定义建造者接口和具体建造者类来实现建造者模式并通过指导者类指导建造过程。建造者模式适用于需要创建复杂对象且对象的构建过程相对稳定但表示可以灵活组合的场景。需要注意定义建造者接口和具体建造者类确保建造过程的正确性和灵活性。同时建造者模式也应避免过度使用以免造成代码冗余。 结构型模式 (Structural Patterns)
结构型模式Structural Patterns是设计模式中的一类它主要关注对象和类的组合以实现更大的结构以及改变或简化类之间的交互方式。这些模式使得不同类和对象之间的关系更加灵活同时也降低了系统的耦合度使系统更易于维护和扩展。
结构型模式在软件开发中起到了重要的作用它们帮助我们在设计阶段选择合适的模式提高系统的设计质量和性能并促进代码的重用和维护。不同的结构型模式适用于不同的场景和需求通过合理使用结构型模式可以让系统更加灵活、可扩展和易于理解。 适配器模式Adapter Pattern
1. 简单介绍
适配器模式Adapter Pattern将一个类的接口转换成客户端所期望的另一个接口使得不兼容的类可以协同工作。
2. 实际问题
假设我们现在有一台笔记本需要插入网线来上网但是笔记本并没有网线接口只有一个 USB 接口网线与 USB 接口并不兼容我们无法直接在笔记本上插入网线需要使用转接器把 USB 接口转换为网线接口 3. 解决方案
适配器模式是一种结构型设计模式它通过创建一个适配器类来转换一个类的接口为客户端所期望的另一个接口。适配器模式主要包含三个角色目标接口Adapter、被适配者Computer和适配器类AdapterNetwork。
// 被适配者类
public class Computer {public void surf(Adapter adapter) {adapter.adapter();System.out.println(this.getClass().getSimpleName() :电脑上网);}
}// 转换器接口
public interface Adapter {public void adapter();
}// 适配器类
public class AdapterNetwork implements Adapter {private final Network network;public AdapterNetwork(Network network) {this.network network;}Overridepublic void adapter() {network.getNet();System.out.println(this.getClass().getSimpleName() :将网口转为USB);}
}// 网口
public class Network {public void getNet() {System.out.println(this.getClass().getSimpleName() 联网);}
}// 调用代码
public class XZ {public static void main(String[] args) {// 创建被适配者对象电脑需要联网Computer computer new Computer();// 创建网口Network network new Network();// 使用适配器将USB口转换为网口Adapter adapter new AdapterNetwork(network);// 电脑插上转换后的网口computer.surf(adapter);}/*Network联网AdapterNetwork:将网口转为USBComputer:电脑上网*/
}4. 类关系图 5. 应用场景
将一个已有的类或接口转换成客户端所期望的另一个接口。在现有系统中需要使用一些已有的类但这些类的接口与系统要求的接口不一致时。适配器模式可以用于系统的扩展和升级将新的功能整合到已有系统中。
6. 易错点
确保适配器类实现了目标接口并正确调用了被适配者类的方法。注意被适配者类的接口与目标接口的兼容性确保适配器类能够正确地适配新的功能。
7. 优缺点
优点
允许将不兼容的类或接口转换为可用的接口提高代码的复用性和灵活性。可以避免修改现有代码降低了代码的风险。
缺点
增加了代码的复杂性引入了适配器类可能会导致类的数量增加。
8. 总结
适配器模式是一种结构型设计模式它通过创建一个适配器类来转换一个类的接口为客户端所期望的另一个接口。适配器模式适用于将不兼容的类或接口转换为可用的接口提高代码的复用性和灵活性避免修改现有代码。需要注意适配器类实现目标接口并正确调用被适配者类的方法。同时适配器模式也应避免过度使用以免引入过多的适配器类增加代码复杂性。 桥接模式Bridge Pattern
1. 简单介绍
桥接模式Bridge Pattern将抽象部分和实现部分分离使它们可以独立变化从而增加系统的灵活性。
2. 实际问题
假设我们要开发一个绘图软件支持绘制不同的图形如圆形、矩形、椭圆等和填充不同的颜色如红色、绿色、蓝色等。如果直接使用继承来实现每种图形和颜色的组合将会导致类爆炸即需要创建大量的类来覆盖所有的组合可能性这会导致代码的复杂性增加。我们希望能够将图形和颜色的绘制过程解耦使得每种图形和颜色可以独立地变化而不影响其他部分。
3. 解决方案
桥接模式是一种结构型设计模式它将抽象部分和实现部分分离使它们可以独立变化从而增加系统的灵活性。桥接模式主要包含两个层次结构抽象化Abstraction和实现化Implementation。
// 抽象化类
public abstract class Shape {protected Color color;public Shape(Color color) {this.color color;}public abstract void draw();
}// 具体抽象化类 - 圆形
public class Circle extends Shape {public Circle(Color color) {super(color);}public void draw() {System.out.print(绘制圆形);color.applyColor();}
}// 具体抽象化类 - 矩形
public class Rectangle extends Shape {public Rectangle(Color color) {super(color);}public void draw() {System.out.print(绘制矩形);color.applyColor();}
}// 实现化接口
public interface Color {void applyColor();
}// 具体实现化类 - 红色
public class RedColor implements Color {public void applyColor() {System.out.println(使用红色);}
}// 具体实现化类 - 绿色
public class GreenColor implements Color {public void applyColor() {System.out.println(使用绿色);}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建具体实现化对象Color redColor new RedColor();Color greenColor new GreenColor();// 创建具体抽象化对象Shape redCircle new Circle(redColor);Shape greenRectangle new Rectangle(greenColor);// 绘制图形redCircle.draw();// Output: 绘制圆形使用红色greenRectangle.draw();// Output: 绘制矩形使用绿色}
}4. 类关系图 5. 应用场景
需要将抽象部分和实现部分分离以便它们可以独立变化从而增加系统的灵活性。当一个类存在多个维度的变化时可以使用桥接模式来简化类的继承关系避免类的爆炸。
6. 易错点
确保抽象化类与实现化类之间的联系避免过多或过少的耦合。在设计类的继承结构时需要合理地选择抽象化和实现化的关系确保系统的灵活性和可维护性。
7. 优缺点
优点
将抽象部分和实现部分分离使它们可以独立变化增加了系统的灵活性和可扩展性。桥接模式避免了类的爆炸现象使得新增具体抽象化类或实现化类更加方便。
缺点
引入桥接模式会增加系统的复杂性需要额外创建抽象化和实现化的类和接口。
8. 总结
桥接模式是一种结构型设计模式它将抽象部分和实现部分分离使它们可以独立变化增加了系统的灵活性和可扩展性。通过桥接模式可以将一个类的多个维度的变化进行解耦避免了类的爆炸现象。需要注意在设计类的继承结构时合理选择抽象化和实现化的关系以确保系统的灵活性和可维护性。桥接模式适用于需要将抽象部分和实现部分分离的场景特别是当一个类存在多个维度的变化时可以使用桥接模式来简化类的继承关系。 组合模式Composite Pattern
1. 简单介绍
组合模式Composite Pattern将对象组合成树形结构以表示“整体-部分”层次关系使得客户端对单个对象和组合对象的使用具有一致性。
2. 实际问题
假设我们正在开发一个文件系统文件系统中包含文件和文件夹两种类型的元素。我们希望能够以树形结构来表示文件系统中的所有元素并且能够对整个文件系统进行统一的操作比如查找文件、删除文件、获取文件大小等。同时我们还希望能够在文件夹中包含其他文件夹形成一个递归的结构。
3. 解决方案
组合模式是一种结构型设计模式它允许将对象组合成树形结构来表示“整体-部分”层次关系。组合模式主要包含两个角色组合对象Composite和叶子对象Leaf。组合对象可以包含叶子对象或其他组合对象形成递归的结构。
// 抽象组件类
public abstract class FileComponent {protected String name;public FileComponent(String name) {this.name name;}public abstract void display(int indentLevel);
}// 叶子对象类 - 文件
public class File extends FileComponent {public final int size;public File(String name, int size) {super(name);this.size size;}public void display(int indentLevel) {StringBuilder indent new StringBuilder();for (int i 0; i indentLevel; i) {indent.append( ); // 每级缩进两个空格}System.out.println(indent File: name , Size: size KB);}
}// 组合对象类 - 文件夹
public class Folder extends FileComponent {public final ListFileComponent components;public Folder(String name) {super(name);components new ArrayList();}public void add(FileComponent component) {components.add(component);}public void remove(FileComponent component) {components.remove(component);}public void display(int indentLevel) {StringBuilder indent new StringBuilder();for (int i 0; i indentLevel; i) {indent.append( ); // 每级缩进两个空格}System.out.println(indent Folder: name);for (FileComponent component : components) {component.display(indentLevel 1);// 递归调用增加缩进级别}}
}public class XZ {public static void main(String[] args) {// 创建文件和文件夹FileComponent file1 new File(File1.txt, 100);FileComponent file2 new File(File2.txt, 50);Folder folder1 new Folder(Folder1);folder1.add(file1);folder1.add(file2);FileComponent file3 new File(File3.txt, 80);FileComponent file4 new File(File4.txt, 120);Folder folder2 new Folder(Folder2);folder2.add(file3);folder2.add(file4);folder2.add(folder1);// 显示文件系统的结构folder2.display(0);}/*Folder: Folder2File: File3.txt, Size: 80 KBFile: File4.txt, Size: 120 KBFolder: Folder1File: File1.txt, Size: 100 KBFile: File2.txt, Size: 50 KB*/
}4. 类关系图 5. 应用场景
希望将对象组合成树形结构以表示“整体-部分”层次关系。需要对整个树形结构进行统一的操作而无需关心具体是叶子对象还是组合对象。当客户端代码需要处理复杂的对象结构时可以使用组合模式来简化代码。
6. 易错点
确保组合对象和叶子对象具有一致的接口以便客户端可以统一操作。在设计组合对象类时需要合理地处理叶子对象和组合对象的关系避免过度递归。
7. 优缺点
优点
允许将对象组合成树形结构表示“整体-部分”层次关系简化了对象结构的表示。可以统一对整个树形结构进行操作使客户端代码更加简洁和灵活。
缺点
引入组合模式会增加系统的复杂性需要额外创建组合对象和叶子对象的类。
8. 总结
组合模式是一种结构型设计模式它允许将对象组合成树形结构来表示“整体-部分”层次关系。通过组合模式可以将叶子对象和组合对象统一表示使得客户端无需关心具体的对象类型。需要注意确保组合对象和叶子对象具有一致的接口以便客户端可以统一操作。组合模式适用于需要表示复杂的对象结构的场景同时需要对整个对象结构进行统一操作的情况。 装饰模式Decorator Pattern
1. 简单介绍
装饰模式Decorator Pattern动态地给对象添加额外的职责是继承的替代方案提供更加灵活的扩展能力。
2. 实际问题
假设我们正在开发一个咖啡店的点单系统。系统中有多种咖啡可以选择并且用户可以根据个人口味选择添加不同的配料比如牛奶、糖、巧克力等。每一种配料都有不同的价格而且用户还可以选择多种配料的组合。我们希望能够以灵活的方式计算出点单的总价并且可以在不修改原有咖啡类的情况下增加新的配料选项。
3. 解决方案
装饰模式是一种结构型设计模式它允许将对象的功能动态地添加到对象中同时不改变其接口。装饰模式主要包含三个角色抽象组件Component、具体组件ConcreteComponent和装饰器Decorator。
// 抽象组件类 - 咖啡
public interface Coffee {double getCost();String getDescription();
}// 装饰器类 - 咖啡装饰器
public abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee decoratedCoffee) {this.decoratedCoffee decoratedCoffee;}public double getCost() {return decoratedCoffee.getCost();}public String getDescription() {return decoratedCoffee.getDescription();}
}// 具体组件类 - 简单咖啡
public class SimpleCoffee implements Coffee {public double getCost() {return 2.0;}public String getDescription() {return 基础咖啡;}
}// 具体装饰器类 - 牛奶装饰器
public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee decoratedCoffee) {super(decoratedCoffee);}public double getCost() {return super.getCost() 1.5;}public String getDescription() {return super.getDescription() , 牛奶;}
}// 具体装饰器类 - 巧克力装饰器
public class ChocolateDecorator extends CoffeeDecorator {public ChocolateDecorator(Coffee decoratedCoffee) {super(decoratedCoffee);}public double getCost() {return super.getCost() 2.0;}public String getDescription() {return super.getDescription() , 巧克力;}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建简单咖啡对象Coffee coffee new SimpleCoffee();// 添加牛奶和巧克力coffee new MilkDecorator(coffee);coffee new ChocolateDecorator(coffee);coffee new MilkDecorator(coffee);// 显示点单地描述和总价System.out.println(商品 coffee.getDescription());System.out.println(花费 coffee.getCost());}/*商品基础咖啡, 牛奶, 巧克力, 牛奶花费7.0*/
}4. 类关系图 5. 应用场景
需要动态地给对象添加功能而且希望在不修改原有代码的情况下增加新的功能。当一个类有多个可选的功能可以使用装饰模式来实现不同的组合。
6. 易错点
确保装饰器类继承自抽象组件类并正确实现装饰器的功能。需要合理地组织装饰器类之间的继承关系确保功能的正确组合。
7. 优缺点
优点
可以动态地给对象添加功能使得功能的增加更加灵活和动态。装饰模式避免了使用继承来扩展功能使得代码更加简洁和易于维护。
缺点
引入装饰器类会增加系统的复杂性需要额外创建装饰器类和维护装饰器之间的关系。
8. 总结
装饰模式是一种结构型设计模式它允许将对象的功能动态地添加到对象中同时不改变其接口。通过装饰模式可以在不修改原有代码的情况下增加新的功能使得功能的增加更加灵活和动态。装饰模式适用于需要动态地给对象添加功能的场景以及有多个可选功能的情况。需要注意在设计装饰器类时合理地组织装饰器类之间的继承关系确保功能的正确组合。 外观模式Facade Pattern
1. 简单介绍
外观模式Facade Pattern为复杂子系统提供一个简单的接口使得子系统更易于使用。
2. 实际问题
假设我们正在开发一个家庭影院系统。家庭影院包含多个设备比如投影仪、音响、DVD播放器等。每次观影时需要打开投影仪、打开音响、打开DVD播放器等一系列操作而且每个设备的控制接口可能都不相同这会导致操作繁琐。我们希望能够提供一个简单的接口让用户只需调用一个方法就可以启动家庭影院系统并开始观影。
3. 解决方案
外观模式是一种结构型设计模式它为子系统提供了一个统一的接口使得子系统更加易于使用。外观模式主要包含一个外观类Facade和多个子系统类SubSystem。
// 子系统类 - 投影仪
public class Projector {public void turnOn() {System.out.println(投影仪开启);}public void turnOff() {System.out.println(投影仪开启关闭);}
}// 子系统类 - 音响系统
public class AudioSystem {public void turnOn() {System.out.println(音响系统开启);}public void turnOff() {System.out.println(音响系统关闭);}
}// 子系统类 - DVD播放器
public class DVDPlayer {public void turnOn() {System.out.println(DVD播放器开启);}public void turnOff() {System.out.println(DVD播放器关闭);}
}// 外观类 - 家庭影院外观
public class HomeTheaterFacade {private final Projector projector;private final AudioSystem audioSystem;private final DVDPlayer dvdPlayer;public HomeTheaterFacade(Projector projector, AudioSystem audioSystem, DVDPlayer dvdPlayer) {this.projector projector;this.audioSystem audioSystem;this.dvdPlayer dvdPlayer;}public void watchMovie() {projector.turnOn();audioSystem.turnOn();dvdPlayer.turnOn();System.out.println(电影开始播放);}public void endMovie() {projector.turnOff();audioSystem.turnOff();dvdPlayer.turnOff();System.out.println(电影结束播放);}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建子系统对象Projector projector new Projector();AudioSystem audioSystem new AudioSystem();DVDPlayer dvdPlayer new DVDPlayer();// 创建家庭影院外观对象HomeTheaterFacade homeTheater new HomeTheaterFacade(projector, audioSystem, dvdPlayer);// 启动家庭影院并观影homeTheater.watchMovie();System.out.println();// 结束观影homeTheater.endMovie();}/*投影仪开启音响系统开启DVD播放器开启电影开始播放投影仪开启关闭音响系统关闭DVD播放器关闭电影结束播放*/
}4. 类关系图 5. 应用场景
当系统中存在复杂的子系统需要对外提供简单的接口时可以使用外观模式。当客户端需要和多个子系统交互时可以使用外观模式来简化交互过程。
6. 易错点
确保外观类中包含了所有子系统的功能以提供统一的接口给客户端调用。外观类不应该包含过多的业务逻辑避免将复杂性转移到外观类中。
7. 优缺点
优点 外观模式提供了一个简单的接口使得客户端更加易于使用子系统。 外观模式将子系统的复杂性隐藏起来使得客户端不需要了解子系统的实现细节。
缺点
外观模式可能导致子系统之间的耦合增加因为外观类需要调用多个子系统的功能。
8. 总结
外观模式是一种结构型设计模式它为子系统提供了一个统一的接口使得子系统更加易于使用。通过外观模式可以将复杂的子系统封装起来提供一个简单的接口给客户端调用。外观模式适用于需要与多个子系统交互或需要简化复杂子系统的场景。需要注意确保外观类中包含了所有子系统的功能同时避免在外观类中添加过多的业务逻辑。 享元模式Flyweight Pattern
1. 简单介绍
享元模式Flyweight Pattern共享对象以减少内存占用提高性能。
2. 实际问题
假设我们正在构建一个简单的绘图应用程序用户可以在画布上绘制圆形和矩形。用户可以选择不同的颜色位置和大小来绘制这些形状。由于用户可以创建许多相似的形状我们需要一种方式来有效地共享相同颜色的形状对象以减少内存使用。
3. 解决方案
享元模式是一种结构型设计模式它通过共享相同类型的对象来减少内存的使用。享元模式主要包含两个角色享元工厂FlyweightFactory和享元对象Flyweight。
// 享元对象接口 - 图形
public interface Shape {void draw();
}// 具体享元对象类 - 圆形
public class Circle implements Shape {// 包含可以被共享的状态private final String color;public Circle(String color) {this.color color;}public void draw() {// 绘制圆形的代码System.out.println(绘制圆形-颜色 color);}
}// 具体享元对象类 - 矩形
public class Rectangle implements Shape {// 包含可以被共享的状态private final String color;public Rectangle(String color) {this.color color;}public void draw() {// 绘制矩形的代码System.out.println(绘制矩形-颜色 color);}
}// 享元工厂类
public class ShapeFactory {private static final MapString, Shape shapeMap new HashMap();public static Shape getShape(String color) {Shape shape shapeMap.get(color);if (shape null) {// 如果不存在具有相同颜色的对象则创建一个新对象if (red.equalsIgnoreCase(color)) {shape new Circle(red);} else if (green.equalsIgnoreCase(color)) {shape new Circle(green);} else if (blue.equalsIgnoreCase(color)) {shape new Circle(blue);} else {shape new Rectangle(black);}// 将新对象存储在享元工厂中以备后续共享shapeMap.put(color, shape);}return shape;}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 获取并绘制图形Shape redCircle ShapeFactory.getShape(red);redCircle.draw();Shape greenCircle ShapeFactory.getShape(green);greenCircle.draw();Shape blueCircle ShapeFactory.getShape(blue);blueCircle.draw();Shape blackRectangle1 ShapeFactory.getShape(black);blackRectangle1.draw();Shape blackRectangle2 ShapeFactory.getShape(black);blackRectangle2.draw();}/*绘制圆形-颜色red绘制圆形-颜色green绘制圆形-颜色blue绘制矩形-颜色black绘制矩形-颜色black*/
}4. 类关系图 5. 应用场景
当系统中存在大量相同或相似的对象并且这些对象可以被共享时可以使用享元模式来减少内存占用。
当需要频繁地创建和销毁对象时可以使用享元模式来提高性能。
6. 易错点
确保享元工厂类能够正确地共享相同类型的对象避免重复创建对象。在使用享元对象时需要注意控制对象的状态确保其在不同场景下的使用正确。
7. 优缺点
优点
享元模式可以减少内存的占用提高系统的性能。通过共享相同类型的对象可以节省对象的创建和销毁时间加快系统的响应速度。
缺点
享元模式会增加系统的复杂性需要额外维护对象的共享状态。如果共享的对象有状态需要在使用时正确管理对象的状态否则可能导致不正确的结果。
8. 总结
享元模式是一种结构型设计模式它通过共享相同类型的对象来减少内存的使用。通过享元模式可以减少重复对象的创建提高系统的性能。享元模式适用于存在大量相同或相似的对象并且这些对象可以被共享的场景。在使用享元模式时需要注意正确管理对象的状态以避免出现不正确的结果。 代理模式Proxy Pattern
1. 简单介绍
代理模式Proxy Pattern为其他对象提供一种代理以控制对这个对象的访问。
2. 实际问题
这里我们直接使用实际业务发开中的场景现有一个查询学生信息的 getStudentInfo() 方法。我们需要在方法之执行前后分别执行相关的业务代码操作以满足开发需求。
3. 解决方案
代理模式是一种结构型设计模式它通过创建一个代理对象来控制对真实对象的访问。代理对象可以在真实对象的操作前后加入自己的逻辑从而实现对真实对象的控制。代理模式主要包含三个角色抽象主题Subject、真实主题RealSubject和代理Proxy。
静态代理
// 业务接口
public interface StudentService {public void getStudentInfo();
}// 业务接口实现类
public class StudentServiceImpl implements StudentService {Overridepublic void getStudentInfo() {System.out.println(获取学生信息);}
}// 静态代理对象
public class StudentServiceImplStaticProxy implements StudentService {private final StudentService studentService;public StudentServiceImplStaticProxy(StudentService studentService) {this.studentService studentService;}Overridepublic void getStudentInfo() {before();studentService.getStudentInfo();after();}public void before() {System.out.println(方法执行前操作);}public void after() {System.out.println(方法执行后操作);}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建代理对象StudentService studentService new StudentServiceImpl();StudentServiceImplStaticProxy proxy new StudentServiceImplStaticProxy(studentService);proxy.getStudentInfo();}// 方法执行前操作// 获取学生信息// 方法执行后操作
}JDK动态代理
// 业务接口
public interface StudentService {public void getStudentInfo();
}// 业务接口实现类
public class StudentServiceImpl implements StudentService {Overridepublic void getStudentInfo() {System.out.println(获取学生信息);}
}// 动态代理对象
public class StudentServiceImplDynamicProxy implements InvocationHandler {private final Object studentService;public StudentServiceImplDynamicProxy(StudentService studentService) {this.studentService studentService;}public StudentService getProxyInstance() {return (StudentService) Proxy.newProxyInstance(studentService.getClass().getClassLoader(), studentService.getClass().getInterfaces(), this);}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object invoke method.invoke(studentService, args);after();return invoke;}public void before() {System.out.println(方法执行前操作);}public void after() {System.out.println(方法执行后操作);}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建代理对象StudentService studentService new StudentServiceImpl();StudentService studentServiceProxy new StudentServiceImplDynamicProxy(studentService).getProxyInstance();studentServiceProxy.getStudentInfo();}// 方法执行前操作// 获取学生信息// 方法执行后操作
}CGLIB动态代理
// 业务接口
public interface StudentService {public void getStudentInfo();
}// 业务接口实现类
public class StudentServiceImpl implements StudentService {Overridepublic void getStudentInfo() {System.out.println(获取学生信息);}
}// 动态代理对象
public class StudentServiceImplCglibDynamicProxy implements MethodInterceptor {private final StudentService studentService;public StudentServiceImplCglibDynamicProxy(StudentService studentService) {this.studentService studentService;}// 用来获取代理对象(创建一个代理对象)public StudentService getProxyInstance() {//可以通过Enhancer对象中的create()方法可以去生成一个类用于生成代理对象Enhancer enhancer new Enhancer();//设置父类(将目标类作为代理类的父类)enhancer.setSuperclass(studentService.getClass());//设置拦截器(回调对象为本身对象)enhancer.setCallback(this);//生成一个代理类对象并返回给调用着return (StudentService) enhancer.create();}Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {before();Object result methodProxy.invokeSuper(o, objects);after();return result;}public void before() {System.out.println(方法执行前操作);}public void after() {System.out.println(方法执行后操作);}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建代理对象StudentService studentService new StudentServiceImpl();StudentService proxy new StudentServiceImplCglibDynamicProxy(studentService).getProxyInstance();proxy.getStudentInfo();}// 方法执行前操作// 获取学生信息// 方法执行后操作
}
// 这里注意JDK版本需为1.84. 类关系图 5. 应用场景 当访问一个对象存在复杂的过程或需要控制访问对象时可以使用代理模式来控制对对象的访问。 当需要在访问真实对象前后加入自己的逻辑时可以使用代理模式来实现增强。
6. 易错点 确保代理对象实现了抽象主题接口并正确实现代理的功能。 确保在真实对象初始化前不执行真实对象的操作以提升性能。
7. 优缺点
优点
代理模式可以控制对真实对象的访问从而实现对真实对象的控制和增强。代理模式可以在真实对象的操作前后加入自己的逻辑从而实现增强。
缺点
代理模式会增加系统的复杂性需要创建额外的代理类来控制对真实对象的访问。
8. 总结
代理模式是一种结构型设计模式它通过创建一个代理对象来控制对真实对象的访问。通过代理模式可以控制对真实对象的访问实现对真实对象的控制和增强。代理模式适用于需要在访问真实对象前后加入自己的逻辑或者需要控制对真实对象的访问的场景。需要注意在代理对象中正确实现代理的功能并确保真实对象的操作在真实对象初始化前不执行以提升性能。 行为型模式 (Behavioral Patterns)
行为型模式Behavioral Patterns是设计模式的一种分类它关注对象之间的交互和责任分配。行为型模式主要用于描述对象之间的通信方式和协作方式以及对象如何相互影响和完成各自的任务。在行为型模式中关注的是对象的行为和算法的分配而不是对象的结构。
每种行为型模式都解决了特定类型的问题可以根据实际的需求选择合适的模式来设计和实现软件系统。这些模式在软件开发中具有广泛的应用能够提高代码的可维护性和扩展性降低代码的耦合度使得系统更加灵活和易于维护。 责任链模式Chain of Responsibility Pattern
1. 简单介绍
责任链模式Chain of Responsibility Pattern将请求的发送者和接收者解耦使得多个对象都有机会处理请求将请求沿着处理链传递直到有一个对象处理它为止。
2. 实际问题
假设你是一个客户服务中心的员工你需要处理客户的问题和请求。有不同类型的问题有些你可以处理有些你需要转给你的主管而有些问题则需要进一步转给高级管理层。你需要一种灵活的方式来处理这些问题并且在将来能够轻松添加新的处理者。
3. 解决方案
在这个示例中Request 类表示客户的请求Handler 是抽象处理者类具有设置下一个处理者的方法和处理请求的抽象方法。LowLevelEmployee、MiddleManager 和 TopManagement 是具体处理者类分别表示低级员工、中级主管和高级管理层。它们分别判断自己是否能够处理请求如果能则处理如果不能则将请求传递给链上的下一个处理者。
// 请求类
class Request {private String requestType;public Request(String requestType) {this.requestType requestType;}public String getRequestType() {return requestType;}
}// 抽象处理者类
abstract class Handler {protected Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler nextHandler;}public abstract void handleRequest(Request request);
}// 具体处理者类低级员工
class LowLevelEmployee extends Handler {Overridepublic void handleRequest(Request request) {if (request.getRequestType().equals(简单问题)) {System.out.println(低级员工处理简单问题);} else {if (nextHandler ! null) {nextHandler.handleRequest(request);}}}
}// 具体处理者类中级主管
class MiddleManager extends Handler {Overridepublic void handleRequest(Request request) {if (request.getRequestType().equals(一般问题)) {System.out.println(中级主管处理一般问题);} else {if (nextHandler ! null) {nextHandler.handleRequest(request);}}}
}// 具体处理者类高级管理层
class TopManagement extends Handler {Overridepublic void handleRequest(Request request) {if (request.getRequestType().equals(复杂问题)) {System.out.println(高级管理层处理复杂问题);} else {System.out.println(无人能处理该问题);}}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建处理者对象Handler lowLevelEmployee new LowLevelEmployee();Handler middleManager new MiddleManager();Handler topManagement new TopManagement();// 设置处理者之间的关系lowLevelEmployee.setNextHandler(middleManager);middleManager.setNextHandler(topManagement);// 创建请求Request request1 new Request(简单问题);Request request2 new Request(一般问题);Request request3 new Request(复杂问题);Request request4 new Request(其他问题);// 处理请求lowLevelEmployee.handleRequest(request1);lowLevelEmployee.handleRequest(request2);lowLevelEmployee.handleRequest(request3);lowLevelEmployee.handleRequest(request4);}/*低级员工处理简单问题中级主管处理一般问题高级管理层处理复杂问题无人能处理该问题*/
}4. 类关系图 5. 应用场景
当有多个对象可以处理同一个请求并且这些对象可以组成一个处理链时可以使用责任链模式。每个对象都尝试处理请求如果自己能处理则处理如果不能则将请求传递给链上的下一个处理者直到有一个处理者处理请求。
6. 易错点
在设置处理者的下一个处理者时需要注意链的顺序确保请求能够正确地沿着链传递。如果链上的处理者没有正确地处理请求或者没有设置下一个处理者可能会导致请求无法得到处理。
7. 优缺点
优点
将请求和处理者解耦客户端不需要知道请求的处理者是谁每个处理者只需关注自己能否处理请求即可。可以动态地组织和拆除处理链灵活性高便于维护和扩展。
缺点
请求可能会在整个链上传递直到有一个处理者处理为止可能导致性能问题。如果链太长可能会导致请求的处理时间较长。
8. 总结
责任链模式是一种行为型设计模式允许多个对象依次处理请求形成一个链式结构。每个处理者负责判断自己是否能够处理请求如果能则处理如果不能则将请求传递给链上的下一个处理者。责任链模式适用于多个对象可以处理同一个请求的场景且每个处理者只需关注自己能否处理请求。在使用责任链模式时需要注意正确设置处理者的顺序和下一个处理者以确保请求能够正确地沿着链传递。 命令模式Command Pattern
1. 简单介绍
命令模式Command Pattern将一个请求封装成一个对象使得可以用不同的请求对客户端进行参数化。
1. 实际问题
假设你正在开发一个文本编辑器应用程序你需要实现多个编辑操作如撤销、重做、剪切、复制等。你需要一种灵活的方式来封装这些编辑操作使得它们能够被单独执行、撤销和重做并且能够轻松地添加新的编辑操作。
3. 解决方案
在这个示例中Command 接口是命令接口包含执行和撤销操作的抽象方法。CutCommand 和 CopyCommand 是具体命令类实现了剪切和复制操作的具体逻辑。Editor 类是接收者表示文本编辑器包含实际的编辑操作。CommandExecutor 类是调用者负责执行命令。
// 命令接口编辑操作
interface Command {void execute();void undo();
}// 具体命令剪切操作
class CutCommand implements Command {private Editor editor;private String text;public CutCommand(Editor editor, String text) {this.editor editor;this.text text;}Overridepublic void execute() {editor.cut(text);}Overridepublic void undo() {editor.undoCut(text);}
}// 具体命令复制操作
class CopyCommand implements Command {private Editor editor;private String text;public CopyCommand(Editor editor, String text) {this.editor editor;this.text text;}Overridepublic void execute() {editor.copy(text);}Overridepublic void undo() {editor.undoCopy(text);}
}// 接收者文本编辑器
class Editor {private String content 我是玄子今年18;public void cut(String text) {content content.replace(text, );System.out.println(剪切 text);}public void copy(String text) {content text;System.out.println(复制 text);}public void undoCut(String text) {content text;System.out.println(撤销剪切 text);}public void undoCopy(String text) {content content.substring(0, content.length() - text.length());System.out.println(撤销复制);}public void display() {System.out.println(当前内容 content);}
}// 调用者命令执行者
class CommandExecutor {private Command command;public void setCommand(Command command) {this.command command;}public void executeCommand() {command.execute();}public void undoCommand() {command.undo();}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建文本编辑器和命令执行者Editor editor new Editor();editor.display();CommandExecutor executor new CommandExecutor();// 创建剪切命令并执行Command cutCommand new CutCommand(editor, 今年18);executor.setCommand(cutCommand);executor.executeCommand();editor.display();// 撤销剪切操作executor.undoCommand();editor.display();// 创建复制命令并执行Command copyCommand new CopyCommand(editor, 我是玄子);executor.setCommand(copyCommand);executor.executeCommand();editor.display();// 撤销复制操作executor.undoCommand();editor.display();}/*当前内容我是玄子今年18剪切今年18当前内容我是玄子撤销剪切今年18当前内容我是玄子今年18复制我是玄子当前内容我是玄子今年18我是玄子撤销复制当前内容我是玄子今年18*/
}4. 类关系图 5. 应用场景
当需要将请求或操作封装成对象实现请求的参数化、传递、撤销和重做时可以使用命令模式。它可以将请求发送者和接收者解耦使得请求可以被单独处理并且可以灵活地添加新的命令类。
6. 易错点
在设计命令接口时需要考虑命令的参数和执行方式以便实现请求的参数化和传递。在实现具体命令类时需要正确调用接收者的方法确保命令可以正确地执行和撤销。
7. 优缺点
优点
将请求和操作封装成对象解耦了请求的发送者和接收者使得命令可以灵活组合和扩展。实现请求的撤销和重做非常方便只需要调用命令对象的撤销方法即可。
缺点
可能会导致命令类的数量增加尤其是在有大量命令和接收者的情况下。如果命令的执行逻辑复杂可能会导致系统的复杂性增加。
8. 总结
命令模式是一种行为型设计模式它将请求或操作封装成一个对象实现请求的参数化、传递、撤销和重做使得请求发送者和接收者解耦。命令模式适用于需要灵活组合和扩展命令的场景或者需要实现请求的撤销和重做的场景。在使用命令模式时需要注意正确设计命令接口和具体命令类确保请求可以正确地传递和执行。 解释器模式Interpreter Pattern
1. 简单介绍
解释器模式Interpreter Pattern定义一种语言的文法并解释语言中的句子。
2. 实际问题
假设你正在开发一个文本处理程序你需要实现一个功能将特定格式的字符串解释为相应的操作或行为。例如用户输入一段字符串 “COPY file.txt TO folder/”你需要将它解释为将 “file.txt” 复制到 “folder/” 目录下。
3. 解决方案
在这个示例中Expression 接口是抽象表达式定义了一个解释方法。TerminalExpression 是终结符表达式表示解释特定的终结符如 “file.txt”。OrExpression 是非终结符表达式表示解释复杂的非终结符如 “COPY” 和 “TO”。InterpreterContext 是解释器环境封装了一个解释器负责解释给定的上下文。
// 抽象表达式解释器接口
interface Expression {boolean interpret(String context);
}// 终结符表达式解释特定的终结符
class TerminalExpression implements Expression {private final String data;public TerminalExpression(String data) {this.data data;}Overridepublic boolean interpret(String context) {return context.contains(data);}
}// 非终结符表达式解释复杂的非终结符
class OrExpression implements Expression {private final Expression expr1;private final Expression expr2;public OrExpression(Expression expr1, Expression expr2) {this.expr1 expr1;this.expr2 expr2;}Overridepublic boolean interpret(String context) {return expr1.interpret(context) || expr2.interpret(context);}
}// 解释器环境上下文
class InterpreterContext {private final Expression expression;public InterpreterContext(Expression expression) {this.expression expression;}public boolean interpret(String context) {return expression.interpret(context);}
}// 调用代码的类
public class XZ {public static void main(String[] args) {Expression expression1 new TerminalExpression(COPY);Expression expression2 new TerminalExpression(TO);Expression expression new OrExpression(expression1, expression2);InterpreterContext interpreterContext new InterpreterContext(expression);System.out.println(interpreterContext.interpret(COPY file.txt TO folder/));}// true
}4. 类关系图 5. 应用场景
当需要解释一些特定语法规则或表达式时可以使用解释器模式。它适用于需要解释复杂表达式的场景可以将一个语言表示为解释器类的层次结构。
6. 易错点
在设计解释器类时需要根据语言的语法规则定义相应的终结符和非终结符表达式确保表达式可以正确地解释。
7. 优缺点
优点
将语言的解释与表达式解耦使得解释过程更加灵活和可扩展。可以灵活地组合表达式实现复杂的解释规则。
缺点
如果语言的规则过于复杂可能会导致解释器类的层次结构很庞大增加系统的复杂性。解释器模式可能不适用于所有的解释场景如果解释逻辑很简单使用解释器模式反而会增加代码的复杂性。
8. 总结
解释器模式是一种行为型设计模式用于解释特定语法规则或表达式。它将语言的解释与表达式解耦使得解释过程更加灵活和可扩展。解释器模式适用于需要解释复杂表达式的场景可以将一个语言表示为解释器类的层次结构。在使用解释器模式时需要根据语言的语法规则定义相应的终结符和非终结符表达式确保表达式可以正确地解释。 迭代器模式Iterator Pattern
1. 简单介绍
迭代器模式Iterator Pattern提供一种顺序访问集合对象元素的方法而不用暴露其内部结构。
2. 实际问题
假设你正在开发一个音乐播放器应用程序你需要管理用户的播放列表。播放列表是一个包含多首音乐的集合你需要一种方法来遍历这个播放列表播放其中的音乐并且能够灵活地切换遍历方式。
3. 解决方案
在这个示例中Iterator 接口是迭代器接口定义了迭代器的两个方法 hasNext() 和 next()。IterableCollection 接口是集合接口定义了一个创建迭代器的方法 createIterator()。MusicPlaylistIterator 是具体迭代器类实现了遍历音乐播放列表的逻辑。MusicPlaylist 是具体集合类包含了音乐播放列表的数据并实现了创建迭代器的方法。
// 迭代器接口
interface IteratorT {boolean hasNext();T next();
}// 集合接口
interface IterableCollectionT {IteratorT createIterator();
}// 具体集合音乐播放列表
class MusicPlaylist implements IterableCollectionString {private final String[] playlist;public MusicPlaylist(String[] playlist) {this.playlist playlist;}Overridepublic IteratorString createIterator() {return new MusicPlaylistIterator(playlist);}
}// 具体迭代器
class MusicPlaylistIterator implements IteratorString {private final String[] playlist;private int currentIndex 0;public MusicPlaylistIterator(String[] playlist) {this.playlist playlist;}Overridepublic boolean hasNext() {return currentIndex playlist.length;}Overridepublic String next() {return playlist[currentIndex];}
}// 调用代码的类
public class XZ {public static void main(String[] args) {String[] playlist {《Slow Down》, 《Shadow Of The Sun》, 《Normal No More 》, 《There For You》, 《STAY》};MusicPlaylist musicPlaylist new MusicPlaylist(playlist);IteratorString iterator musicPlaylist.createIterator();while (iterator.hasNext()) {System.out.println(iterator.next());}}/*《Slow Down》《Shadow Of The Sun》《Normal No More 》《There For You》《STAY》*/
}4. 类关系图 5. 应用场景
当需要遍历一个集合而又不想暴露其内部表示时可以使用迭代器模式。迭代器模式可以将遍历操作封装在迭代器中使得客户端可以逐个访问集合的元素而不需要了解集合的内部结构。
6. 易错点
在实现迭代器类时需要确保迭代器能够正确遍历集合并在遍历结束后返回正确的状态。在实现集合类时需要正确创建迭代器对象并确保迭代器能够访问集合的元素。
7. 优缺点
优点
将集合的遍历操作封装在迭代器中使得客户端可以逐个访问集合的元素而不需要了解集合的内部结构。迭代器模式增加了集合类的灵活性可以通过不同的迭代器实现不同的遍历方式。
缺点
对于简单的集合类使用迭代器模式可能会增加代码的复杂性。
8. 总结
迭代器模式是一种行为型设计模式用于提供一种顺序访问集合中各个元素的方法而不需要暴露其内部表示。迭代器模式适用于需要遍历一个集合而又不想暴露其内部结构的场景。它将集合的遍历操作封装在迭代器中使得客户端可以逐个访问集合的元素并且能够灵活地切换遍历方式。在使用迭代器模式时需要注意确保迭代器能够正确遍历集合并且集合类能够正确创建迭代器对象。 中介者模式Mediator Pattern
1. 简单介绍
中介者模式Mediator Pattern用一个中介对象来封装一系列对象之间的交互使得对象之间不再直接相互引用降低耦合性。
2. 实际问题
假设你正在开发一个多用户聊天室应用程序用户可以在聊天室中发送消息。每个用户可以看到其他用户发送的消息并且可以回复消息。你需要一种方式来管理用户之间的通信并确保消息能够正确地传递给目标用户。
3. 解决方案
在这个示例中ChatRoomMediator 接口是中介者接口定义了一个发送消息的方法 sendMessage()。ChatRoom 是具体中介者类表示聊天室它实现了发送消息的逻辑。User 是用户类每个用户都有一个名字和一个中介者当用户发送消息时调用中介者的 sendMessage() 方法来发送消息。
// 中介者接口
interface ChatRoomMediator {void sendMessage(String message, User user);
}// 具体中介者聊天室
class ChatRoom implements ChatRoomMediator {Overridepublic void sendMessage(String message, User user) {System.out.println(user.getName() 发送消息 message);}
}// 用户类
class User {private String name;private ChatRoomMediator mediator;public User(String name, ChatRoomMediator mediator) {this.name name;this.mediator mediator;}public String getName() {return name;}public void sendMessage(String message) {mediator.sendMessage(message, this);}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建聊天室中介者ChatRoomMediator chatRoom new ChatRoom();// 创建用户User user1 new User(User1, chatRoom);User user2 new User(User2, chatRoom);User user3 new User(User3, chatRoom);// 用户发送消息user1.sendMessage(Hello everyone!);user2.sendMessage(Hi User1!);user3.sendMessage(Nice to meet you all!);}/*User1 发送消息Hello everyone!User2 发送消息Hi User1!User3 发送消息Nice to meet you all!*/
}4. 类关系图 5. 应用场景
当多个对象之间存在复杂的交互关系且对象之间不直接相互交互而是通过一个中介者来进行通信时可以使用中介者模式。中介者模式可以减少对象之间的耦合性并且使得系统更易于维护和扩展。
6. 易错点
在设计中介者接口时需要考虑对象之间交互的方式和需要传递的参数确保中介者能够正确地传递消息给目标对象。
7. 优缺点
优点
将对象之间的交互封装在中介者中减少了对象之间的耦合性使得系统更易于维护和扩展。中介者模式可以将复杂的交互关系简化使得系统的逻辑更清晰。
缺点
如果中介者对象过于庞大可能会导致中介者本身的复杂性增加影响系统的性能和可维护性。
8. 总结
中介者模式是一种行为型设计模式用于封装一组对象之间的交互。它定义了一个中介者对象用于管理对象之间的通信减少对象之间的耦合性并且使得系统更易于维护和扩展。中介者模式适用于多个对象之间存在复杂的交互关系且对象之间不直接相互交互的场景。在使用中介者模式时需要注意设计中介者接口确保中介者能够正确地传递消息给目标对象。 备忘录模式Memento Pattern
1. 简单介绍
备忘录模式Memento Pattern在不破坏封装性的前提下捕获一个对象的内部状态以便在需要时恢复该状态。
2. 实际问题
假设你正在开发一个文本编辑器应用程序用户可以在编辑器中输入和编辑文本。用户可能会频繁地对文本进行修改但是有时候可能会误操作或者想要撤销之前的修改。你需要一种方法来保存编辑器的历史状态以便用户可以随时撤销到之前的状态。
3. 解决方案
在这个示例中EditorMemento 是备忘录类用于保存文本编辑器的状态。TextEditor 是发起人类表示文本编辑器它包含了编辑器的内容和保存状态、恢复状态的方法。EditorHistory 是管理者类用于保存和恢复编辑器的历史状态。
// 备忘录保存编辑器的状态
class EditorMemento {private String content;public EditorMemento(String content) {this.content content;}public String getContent() {return content;}
}// 发起人文本编辑器
class TextEditor {private String content;public void write(String text) {content text;}public String getContent() {return content;}public EditorMemento save() {return new EditorMemento(content);}public void restore(EditorMemento memento) {content memento.getContent();}
}// 管理者保存和恢复编辑器状态
class EditorHistory {private StackEditorMemento history new Stack();public void save(EditorMemento memento) {history.push(memento);}public EditorMemento pop() {return history.pop();}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建文本编辑器与备忘录TextEditor editor new TextEditor();EditorHistory history new EditorHistory();// 编辑并保存文本editor.write(第一行文字\n);history.save(editor.save());editor.write(第二行文字\n);history.save(editor.save());editor.write(第三行文字\n);// 恢复最后一次保存的状态editor.restore(history.pop());// 输出结果第一行文字\n第二行文字\nSystem.out.println(editor.getContent());}
}4. 类关系图 5. 应用场景
当需要在不破坏对象封装性的前提下保存和恢复对象的内部状态时可以使用备忘录模式。备忘录模式允许在后续的时间点将对象恢复到之前保存的状态适用于需要撤销或回滚操作的场景。
6. 易错点
在实现备忘录类时需要确保备忘录对象保存的状态可以被外部访问但不能被直接修改以保证备忘录对象的封装性。
7. 优缺点
优点
允许在后续的时间点将对象恢复到之前保存的状态提供了撤销或回滚操作的能力。对象的状态保存在备忘录中可以避免在发起人中直接暴露对象的内部状态。
缺点
如果备忘录对象过多可能会导致内存消耗较大。如果备忘录对象需要频繁创建和恢复可能会影响系统的性能。
8. 总结
备忘录模式是一种行为型设计模式用于在不破坏封装性的前提下保存和恢复对象的内部状态。备忘录模式允许在后续的时间点将对象恢复到之前保存的状态提供了撤销或回滚操作的能力。它适用于需要保存历史状态以便在后续操作中恢复状态的场景。在使用备忘录模式时需要注意备忘录对象的封装性确保状态可以被外部访问但不能被直接修改。 观察者模式Observer Pattern
观察者模式Observer Pattern定义对象之间的一种一对多的依赖关系当一个对象状态发生变化时所有依赖它的对象都会得到通知并自动更新。
1. 实际问题
假设你正在开发一个天气预报应用程序你需要实现一个功能让用户可以订阅并接收实时的天气信息。用户可以选择订阅多个城市的天气信息并在天气发生变化时及时收到通知。
3. 解决方案
在这个示例中Subject 是主题接口定义了添加观察者、移除观察者和通知观察者的方法。Observer 是观察者接口定义了更新状态的方法。WeatherForecast 是具体主题类表示天气预报它维护了一个观察者列表并在状态发生变化时通知观察者。User 是具体观察者类表示用户当收到通知时更新天气预报。
// 主题接口被观察者
interface Subject {void addObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}// 观察者接口
interface Observer {void update(String message);
}// 具体主题天气预报
class WeatherForecast implements Subject {private ListObserver observers new ArrayList();private String weatherMessage;Overridepublic void addObserver(Observer observer) {observers.add(observer);}Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(weatherMessage);}}public void setWeatherMessage(String weatherMessage) {this.weatherMessage weatherMessage;notifyObservers();}
}// 具体观察者用户
class User implements Observer {private String name;public User(String name) {this.name name;}Overridepublic void update(String message) {System.out.println(name 收到天气预报 message);}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建天气预报对象WeatherForecast weatherForecast new WeatherForecast();// 创建观察者对象User user1 new User(张三);User user2 new User(李四);// 添加观察者weatherForecast.addObserver(user1);weatherForecast.addObserver(user2);// 设置天气预报信息触发通知weatherForecast.setWeatherMessage(明天有雨);// 输出结果// 张三 收到天气预报明天有雨// 李四 收到天气预报明天有雨// 移除观察者user2weatherForecast.removeObserver(user2);// 设置天气预报信息触发通知weatherForecast.setWeatherMessage(后天晴朗);// 输出结果// 张三 收到天气预报后天晴朗}
}4. 类关系图 5. 应用场景
当一个对象的状态发生变化时需要通知多个依赖对象并且不希望主题和观察者之间紧密耦合时可以使用观察者模式。观察者模式允许主题独立地改变状态而不影响观察者。
6. 易错点
在实现观察者模式时需要注意主题对象应该维护观察者列表并在状态发生变化时通知观察者。观察者的更新逻辑应该与主题的逻辑分离确保观察者和主题之间解耦。
7. 优缺点
优点
观察者模式实现了一种一对多的依赖关系允许主题独立地改变状态而不影响观察者。可以动态地添加和移除观察者使得系统更灵活和可扩展。
缺点
如果观察者较多或观察者的更新逻辑较复杂可能会导致通知观察者的时间较长影响系统的性能。如果观察者和主题之间存在循环依赖可能会导致系统的复杂性增加。
8. 总结
观察者模式是一种行为型设计模式用于实现一种一对多的依赖关系当一个对象的状态发生变化时其依赖对象观察者会自动收到通知并更新。观察者模式允许主题被观察者和观察者之间解耦使得主题可以独立地改变状态而不影响观察者。它适用于需要通知多个依赖对象的场景如天气预报、事件处理等。在实现观察者模式时需要注意主题对象维护观察者列表并在状态发生变化时通知观察者同时确保观察者和主题之间解耦。 状态模式State Pattern
1. 简单介绍
状态模式State Pattern允许对象在内部状态改变时改变其行为使得对象看起来像是修改了其类。
2. 实际问题
假设你正在开发一个电梯控制系统电梯有多个状态包括开门状态、关门状态、运行状态和停止状态。在不同的状态下电梯会有不同的行为比如在运行状态下电梯可以响应楼层按钮而在停止状态下电梯只能等待用户操作。
3. 解决方案
在这个示例中ElevatorState 是状态接口定义了电梯的四种状态开门、关门、上行和下行。OpenState、CloseState、RunningState 和 StoppedState 是具体状态类分别表示电梯的四种状态它们实现了状态接口的方法。Elevator 是环境类表示电梯它维护了当前的状态并提供了可以改变状态的方法。
// 状态接口
interface ElevatorState {void openDoor();void closeDoor();void goUp();void goDown();
}// 具体状态开门状态
class OpenState implements ElevatorState {Overridepublic void openDoor() {System.out.println(电梯已经是开门状态);}Overridepublic void closeDoor() {System.out.println(电梯关门);}Overridepublic void goUp() {System.out.println(电梯开始上行);}Overridepublic void goDown() {System.out.println(电梯开始下行);}
}// 具体状态关门状态
class CloseState implements ElevatorState {Overridepublic void openDoor() {System.out.println(电梯开门);}Overridepublic void closeDoor() {System.out.println(电梯已经是关门状态);}Overridepublic void goUp() {System.out.println(电梯开始上行);}Overridepublic void goDown() {System.out.println(电梯开始下行);}
}// 具体状态运行状态
class RunningState implements ElevatorState {Overridepublic void openDoor() {System.out.println(电梯不能在运行时开门);}Overridepublic void closeDoor() {System.out.println(电梯不能在运行时关门);}Overridepublic void goUp() {System.out.println(电梯继续上行);}Overridepublic void goDown() {System.out.println(电梯继续下行);}
}// 具体状态停止状态
class StoppedState implements ElevatorState {Overridepublic void openDoor() {System.out.println(电梯开门);}Overridepublic void closeDoor() {System.out.println(电梯关门);}Overridepublic void goUp() {System.out.println(电梯开始上行);}Overridepublic void goDown() {System.out.println(电梯开始下行);}
}// 环境类电梯
class Elevator {private ElevatorState currentState;public Elevator() {currentState new StoppedState();}public void setState(ElevatorState state) {currentState state;}public void openDoor() {currentState.openDoor();}public void closeDoor() {currentState.closeDoor();}public void goUp() {currentState.goUp();}public void goDown() {currentState.goDown();}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建电梯对象Elevator elevator new Elevator();// 设置电梯状态为打开elevator.setState(new OpenState());elevator.openDoor(); // 电梯已经是开门状态// 设置电梯状态为关闭elevator.setState(new CloseState());elevator.closeDoor(); // 电梯关门// 设置电梯状态为运行elevator.setState(new RunningState());elevator.goUp(); // 电梯继续上行// 设置电梯状态为停止elevator.setState(new StoppedState());elevator.openDoor(); // 电梯开门}
}4. 类关系图 5. 应用场景
当一个对象的行为随着内部状态的改变而改变时可以使用状态模式。状态模式可以将对象的行为封装在不同的状态类中使得状态转换更加灵活和可扩展。
6. 易错点
在实现状态模式时需要确保环境类正确维护当前的状态并在状态改变时能够正确地调用相应状态的方法。
7. 优缺点
优点
将对象的行为封装在不同的状态类中使得状态转换更加灵活和可扩展。避免了使用大量的条件语句判断对象的状态使得代码更加清晰和易于维护。
缺点
当状态较多或状态之间转换较为复杂时可能会导致状态类的增加增加了系统的复杂性。
8. 总结
状态模式是一种行为型设计模式它允许一个对象在其内部状态改变时改变其行为。状态模式将对象的行为封装在不同的状态类中当对象的状态发生改变时它的行为也会随之改变。状态模式适用于当对象的行为随着内部状态的改变而改变的场景比如电梯控制系统、游戏角色状态等。在实现状态模式时需要确保环境类正确维护当前的状态并在状态改变时能够正确地调用相应状态的方法。 策略模式Strategy Pattern
1. 简单介绍
策略模式Strategy Pattern定义一系列算法并使其可以相互替换使得算法的变化独立于使用算法的客户端。
2. 实际问题
假设你正在开发一个电商网站用户在购买商品时可以选择不同的支付方式比如支付宝、微信支付、信用卡支付等。你需要设计一个灵活的支付系统使得可以根据用户选择的支付方式来执行相应的支付逻辑。
3. 解决方案
在这个示例中PaymentStrategy 是支付策略接口定义了支付的方法 pay()。AlipayStrategy 和 WechatPayStrategy 是具体支付策略类表示支付宝支付和微信支付它们实现了支付策略接口的方法。PaymentContext 是上下文类表示支付系统它包含了一个支付策略的引用并提供了设置支付策略和执行支付的方法。
// 支付策略接口
interface PaymentStrategy {void pay(double amount);
}// 具体支付策略支付宝支付
class AlipayStrategy implements PaymentStrategy {Overridepublic void pay(double amount) {System.out.println(使用支付宝支付 amount 元);}
}// 具体支付策略微信支付
class WechatPayStrategy implements PaymentStrategy {Overridepublic void pay(double amount) {System.out.println(使用微信支付 amount 元);}
}// 上下文类支付系统
class PaymentContext {private final PaymentStrategy strategy;public PaymentContext(PaymentStrategy strategy) {this.strategy strategy;}public void executePayment(double amount) {strategy.pay(amount);}
}// 调用代码的类
public class XZ {public static void main(String[] args) {PaymentContext alipay new PaymentContext(new AlipayStrategy());alipay.executePayment(12);PaymentContext wechatPay new PaymentContext(new WechatPayStrategy());wechatPay.executePayment(24);}/*使用支付宝支付12.0元使用微信支付24.0元*/
}4. 类关系图 5. 应用场景
当有多个算法可以选择并且需要在运行时根据不同的条件选择合适的算法时可以使用策略模式。策略模式允许客户端在运行时选择合适的算法而不需要改变客户端的代码。
6. 易错点
在实现策略模式时需要确保策略类实现了相同的接口以便在上下文类中可以统一使用。
7. 优缺点
优点
将算法封装在独立的策略类中使得算法可以互相替换增加了系统的灵活性和可扩展性。客户端可以在运行时选择合适的算法而不需要改变客户端的代码提高了系统的可维护性和扩展性。
缺点
当策略较多或策略之间逻辑较复杂时可能会导致策略类的增加增加了系统的复杂性。
8. 总结
策略模式是一种行为型设计模式它定义了一系列算法族并将每个算法封装在独立的策略类中使得算法可以互相替换。策略模式适用于当有多个算法可以选择并且需要在运行时根据不同的条件选择合适的算法的场景。在实现策略模式时需要确保策略类实现了相同的接口以便在上下文类中可以统一使用。 模板方法模式Template Method Pattern
1. 简单介绍
模板方法模式Template Method Pattern定义一个算法的骨架将一些步骤的实现延迟到子类中。
2. 实际问题
假设你正在开发一个咖啡店点单系统该系统需要支持不同类型的咖啡如美式咖啡、拿铁咖啡和卡布奇诺等。不同类型的咖啡在制作过程中可能有一些不同的步骤但整体制作流程是相同的。你希望设计一个通用的咖啡制作模板使得每种类型的咖啡可以共享通用的制作流程并且允许子类来实现特定类型咖啡的特殊步骤。
3. 解决方案
在这个示例中CoffeeTemplate 是咖啡制作模板定义了咖啡的制作流程其中 makeCoffee() 方法是模板方法包含了制作咖啡的通用流程而 boilWater()、brewCoffee()、pourIntoCup() 和 addCondiments() 是具体步骤其中 brewCoffee() 和 addCondiments() 是抽象方法由子类具体实现。AmericanoCoffee 和 LatteCoffee 是具体咖啡类分别表示美式咖啡和拿铁咖啡它们继承自咖啡制作模板并实现了特定类型咖啡的特殊步骤。
// 咖啡制作模板
abstract class CoffeeTemplate {public final void makeCoffee() {boilWater();brewCoffee();pourIntoCup();addCondiments();}protected void boilWater() {System.out.println(烧水);}protected abstract void brewCoffee();protected void pourIntoCup() {System.out.println(倒入杯中);}protected abstract void addCondiments();
}// 具体咖啡拿铁咖啡
class LatteCoffee extends CoffeeTemplate {Overrideprotected void brewCoffee() {System.out.println(冲泡拿铁咖啡);}Overrideprotected void addCondiments() {System.out.println(加入牛奶);}
}// 具体咖啡美式咖啡
class AmericanoCoffee extends CoffeeTemplate {Overrideprotected void brewCoffee() {System.out.println(冲泡美式咖啡);}Overrideprotected void addCondiments() {// 美式咖啡不加调料}
}// 调用代码的类
public class XZ {public static void main(String[] args) {CoffeeTemplate americanoCoffee new AmericanoCoffee();americanoCoffee.makeCoffee();System.out.println();CoffeeTemplate latteCoffee new LatteCoffee();latteCoffee.makeCoffee();}/*烧水冲泡美式咖啡倒入杯中烧水冲泡拿铁咖啡倒入杯中加入牛奶*/
}4. 类关系图 5. 应用场景
当有一个算法的流程固定但其中某些步骤可能会有所不同并且希望通过子类来实现这些不同的步骤时可以使用模板方法模式。模板方法模式允许将算法的结构封装在一个模板中而将具体的实现细节交给子类。
6. 易错点
在实现模板方法模式时需要确保模板方法是 final 或者不能被子类覆盖以防止子类改变算法的骨架。
7. 优缺点
优点
将算法的骨架封装在一个模板方法中使得算法的结构更加清晰和易于理解。允许子类在不改变算法结构的情况下重新定义算法的某些步骤增加了系统的灵活性和可扩展性。
缺点
当模板方法过于复杂或有过多的具体步骤时可能会导致子类的增加增加了系统的复杂性。
8. 总结
模板方法模式是一种行为型设计模式它定义了一个算法的骨架并将一些步骤延迟到子类中实现。模板方法模式适用于当有一个算法的流程固定但其中某些步骤可能会有所不同的场景。在实现模板方法模式时需要确保模板方法是 final 或者不能被子类覆盖以防止子类改变算法的骨架。 访问者模式Visitor Pattern
1. 简单介绍
访问者模式Visitor Pattern在不改变对象结构的前提下定义作用于某个对象结构中的各个元素的操作。
2. 实际问题
假设你正在开发一个旅游景点导览系统该系统需要展示不同类型的景点如博物馆、动物园和公园等。每种类型的景点都有不同的展示方式比如博物馆需要展示历史文物动物园需要展示各种动物公园需要展示美丽的花园。你希望设计一个通用的展示系统使得可以根据不同类型的景点来展示不同的内容。
3. 解决方案
在这个示例中Element 是元素接口定义了接受访问者的方法 accept(Visitor visitor)。Museum、Zoo 和 Park 是具体元素类表示博物馆、动物园和公园它们实现了元素接口的方法并在 accept 方法中将自身作为参数传递给访问者。Visitor 是访问者接口定义了访问者的方法 visit(Museum museum)、visit(Zoo zoo) 和 visit(Park park)。DisplayVisitor 是具体访问者类表示展示访问者它实现了访问者接口的方法并在每个方法中根据具体元素的类型展示相应的内容。
// 元素接口
interface Element {void accept(Visitor visitor);
}// 具体元素博物馆
class Museum implements Element {Overridepublic void accept(Visitor visitor) {visitor.visit(this);}// 博物馆特有方法public String getExhibition() {return 历史文物展览;}
}// 具体元素动物园
class Zoo implements Element {Overridepublic void accept(Visitor visitor) {visitor.visit(this);}// 动物园特有方法public String getAnimals() {return 狮子、大象、长颈鹿等;}
}// 具体元素公园
class Park implements Element {Overridepublic void accept(Visitor visitor) {visitor.visit(this);}// 公园特有方法public String getGarden() {return 美丽的花园;}
}// 访问者接口
interface Visitor {void visit(Museum museum);void visit(Zoo zoo);void visit(Park park);
}// 具体访问者展示访问者
class DisplayVisitor implements Visitor {Overridepublic void visit(Museum museum) {System.out.println(展示博物馆展览内容 museum.getExhibition());}Overridepublic void visit(Zoo zoo) {System.out.println(展示动物园动物 zoo.getAnimals());}Overridepublic void visit(Park park) {System.out.println(展示公园花园 park.getGarden());}
}// 调用代码的类
public class XZ {public static void main(String[] args) {// 创建元素对象Element museum new Museum();Element zoo new Zoo();Element park new Park();// 创建访问者对象Visitor displayVisitor new DisplayVisitor();// 对元素应用访问者museum.accept(displayVisitor);zoo.accept(displayVisitor);park.accept(displayVisitor);}/*展示博物馆展览内容历史文物展览展示动物园动物狮子、大象、长颈鹿等展示公园花园美丽的花园*/
}4. 类关系图 5. 应用场景
当有一个数据结构中包含不同类型的元素并且希望根据不同的元素执行不同的操作时可以使用访问者模式。访问者模式允许将算法从数据结构中分离出来使得可以在不改变数据结构的情况下定义新的算法。
6. 易错点
在实现访问者模式时需要确保每个具体元素类都正确实现了接受访问者的方法并在其中调用访问者的对应方法。
7. 优缺点
优点
将算法从数据结构中分离出来增加了系统的灵活性和可扩展性。新的访问者可以在不改变数据结构的情况下定义新的操作。
缺点
当元素较多或元素的类型较复杂时可能会导致访问者类的增加增加了系统的复杂性。
8. 总结
访问者模式是一种行为型设计模式它允许将算法从数据结构中分离出来使得可以在不改变数据结构的情况下定义新的算法。访问者模式适用于当有一个数据结构中包含不同类型的元素并且希望根据不同的元素执行不同的操作的场景。在实现访问者模式时需要确保每个具体元素类都正确实现了接受访问者的方法并在其中调用访问者的对应方法。 必要性拓展Necessity Expansion
简单工厂模式Simple Factory Pattern
1. 简单介绍
简单工厂模式Simple Factory Pattern虽然它不在 GoF 的列表中但在实际开发中简单工厂模式是一种经常被使用的设计模式。它简化了对象的创建过程提高了代码的可维护性和扩展性。
2. 实际问题
假设你正在开发一个计算器应用程序用户可以输入两个操作数和运算符然后应用程序会根据输入的运算符进行相应的计算并返回结果。不同的运算符对应不同的计算方法例如加法、减法、乘法和除法等。你希望设计一个通用的计算器工厂根据用户输入的运算符生产出相应的计算器对象从而实现不同运算的计算功能。
3. 实现方式
// 运算器接口
interface Operator {double calculate(double operand1, double operand2);
}// 具体运算器加法运算器
class AdditionOperator implements Operator {Overridepublic double calculate(double operand1, double operand2) {return operand1 operand2;}
}// 具体运算器减法运算器
class SubtractionOperator implements Operator {Overridepublic double calculate(double operand1, double operand2) {return operand1 - operand2;}
}// 具体运算器乘法运算器
class MultiplicationOperator implements Operator {Overridepublic double calculate(double operand1, double operand2) {return operand1 * operand2;}
}// 具体运算器除法运算器
class DivisionOperator implements Operator {Overridepublic double calculate(double operand1, double operand2) {if (operand2 0) {throw new IllegalArgumentException(除数不能为零);}return operand1 / operand2;}
}// 简单工厂类
class CalculatorFactory {public static Operator createOperator(String operatorType) {switch (operatorType) {case :return new AdditionOperator();case -:return new SubtractionOperator();case *:return new MultiplicationOperator();case /:return new DivisionOperator();default:throw new IllegalArgumentException(不支持的运算符 operatorType);}}
}// 调用代码
public class XZ {public static void main(String[] args) {Operator operator1 CalculatorFactory.createOperator();System.out.println(operator1.calculate(1, 2));Operator operator2 CalculatorFactory.createOperator(-);System.out.println(operator2.calculate(1, 2));Operator operator3 CalculatorFactory.createOperator(*);System.out.println(operator3.calculate(1, 2));Operator operator4 CalculatorFactory.createOperator(/);System.out.println(operator4.calculate(1, 2));// Operator operator5 CalculatorFactory.createOperator(%);// System.out.println(operator5.calculate(1, 2));// 执行没有的 Operator 抛出异常}
}在这个示例中Operator 是运算器接口定义了一个 calculate() 方法来进行运算。AdditionOperator、SubtractionOperator、MultiplicationOperator 和 DivisionOperator 是具体运算器类分别表示加法运算器、减法运算器、乘法运算器和除法运算器它们都实现了运算器接口的方法。CalculatorFactory 是简单工厂类它通过 createOperator() 方法来根据用户输入的运算符类型创建相应的运算器对象。
4. 类关系图 #mermaid-svg-CKEJnLb9oAuebMa6 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-CKEJnLb9oAuebMa6 .error-icon{fill:#552222;}#mermaid-svg-CKEJnLb9oAuebMa6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CKEJnLb9oAuebMa6 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-CKEJnLb9oAuebMa6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CKEJnLb9oAuebMa6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CKEJnLb9oAuebMa6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CKEJnLb9oAuebMa6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CKEJnLb9oAuebMa6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CKEJnLb9oAuebMa6 .marker.cross{stroke:#333333;}#mermaid-svg-CKEJnLb9oAuebMa6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CKEJnLb9oAuebMa6 g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-CKEJnLb9oAuebMa6 g.classGroup text .title{font-weight:bolder;}#mermaid-svg-CKEJnLb9oAuebMa6 .nodeLabel,#mermaid-svg-CKEJnLb9oAuebMa6 .edgeLabel{color:#131300;}#mermaid-svg-CKEJnLb9oAuebMa6 .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-CKEJnLb9oAuebMa6 .label text{fill:#131300;}#mermaid-svg-CKEJnLb9oAuebMa6 .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-CKEJnLb9oAuebMa6 .classTitle{font-weight:bolder;}#mermaid-svg-CKEJnLb9oAuebMa6 .node rect,#mermaid-svg-CKEJnLb9oAuebMa6 .node circle,#mermaid-svg-CKEJnLb9oAuebMa6 .node ellipse,#mermaid-svg-CKEJnLb9oAuebMa6 .node polygon,#mermaid-svg-CKEJnLb9oAuebMa6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CKEJnLb9oAuebMa6 .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-CKEJnLb9oAuebMa6 g.clickable{cursor:pointer;}#mermaid-svg-CKEJnLb9oAuebMa6 g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-CKEJnLb9oAuebMa6 g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-CKEJnLb9oAuebMa6 .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-CKEJnLb9oAuebMa6 .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-CKEJnLb9oAuebMa6 .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-CKEJnLb9oAuebMa6 .dashed-line{stroke-dasharray:3;}#mermaid-svg-CKEJnLb9oAuebMa6 #compositionStart,#mermaid-svg-CKEJnLb9oAuebMa6 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-CKEJnLb9oAuebMa6 #compositionEnd,#mermaid-svg-CKEJnLb9oAuebMa6 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-CKEJnLb9oAuebMa6 #dependencyStart,#mermaid-svg-CKEJnLb9oAuebMa6 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-CKEJnLb9oAuebMa6 #dependencyStart,#mermaid-svg-CKEJnLb9oAuebMa6 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-CKEJnLb9oAuebMa6 #extensionStart,#mermaid-svg-CKEJnLb9oAuebMa6 .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-CKEJnLb9oAuebMa6 #extensionEnd,#mermaid-svg-CKEJnLb9oAuebMa6 .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-CKEJnLb9oAuebMa6 #aggregationStart,#mermaid-svg-CKEJnLb9oAuebMa6 .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-CKEJnLb9oAuebMa6 #aggregationEnd,#mermaid-svg-CKEJnLb9oAuebMa6 .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-CKEJnLb9oAuebMa6 .edgeTerminals{font-size:11px;}#mermaid-svg-CKEJnLb9oAuebMa6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} «create» «create» «create» «create» AdditionOperator calculate(double, double) AdditionOperator() CalculatorFactory createOperator(String) CalculatorFactory() DivisionOperator calculate(double, double) DivisionOperator() MultiplicationOperator calculate(double, double) MultiplicationOperator() «Interface» Operator calculate(double, double) SubtractionOperator calculate(double, double) SubtractionOperator() XZ main(String[]) XZ() 5. 应用场景
当需要根据不同的条件创建不同类型的对象时可以使用简单工厂模式。简单工厂模式将对象的创建逻辑封装在工厂类中使得客户端不需要知道具体的对象创建过程只需要通过工厂类来获取对象。
6. 易错点
在实现简单工厂模式时需要注意工厂类的职责它应该负责根据条件创建相应的对象而不应该承担过多的业务逻辑。
7. 优缺点
优点
将对象的创建逻辑封装在工厂类中使得客户端不需要关心对象的具体创建过程降低了客户端和具体对象的耦合。简单工厂模式可以通过工厂类来统一管理对象的创建便于代码的维护和管理。
缺点
如果需要添加新的运算器类型需要修改工厂类的代码这可能违反了开闭原则导致工厂类的修改。
8. 总结
简单工厂模式是一种创建型设计模式它通过一个工厂类来创建不同类型的对象使得客户端不需要关心对象的具体创建过程。简单工厂模式适用于当需要根据不同的条件创建不同类型的对象时。在实现简单工厂模式时需要注意工厂类的职责它应该负责根据条件创建相应的对象而不应该承担过多的业务逻辑。虽然简单工厂模式有一些优点但也有一些缺点例如如果需要添加新的对象类型可能需要修改工厂类的代码这可能违反了开闭原则。因此在应用简单工厂模式时需要权衡考虑选择合适的设计方案。 空对象模式Null Object Pattern
1. 简单介绍
空对象模式Null Object Pattern虽然它不在 GoF 的列表中但在实际开发中我们通常使用空对象模式Null Object Pattern来替代传统的null值或者抛出异常的做法。空对象模式是一种创建一个默认对象的设计模式这个默认对象包含了类似于对null的处理但是避免了空指针异常的出现。如果有NULL对象被调用就会返回一个默认的对象而不是null值。
2. 实际问题
在一个电商网站中我们需要对商品进行分类、下单、支付等操作。当有用户查询或者购买不存在的商品时我们需要能够处理该异常情况确保不会出现空指针异常等错误同时也需要保证程序正常运行。
3. 解决方案
// 商品抽象类
public abstract class Product {protected String name;protected double price;public abstract String getName();public abstract double getPrice();
}// 商品类
public class ConcreteProduct extends Product {public ConcreteProduct(String name, double price) {this.name name;this.price price;}public String getName() {return name;}public double getPrice() {return price;}
}// 空商品类
public class NullProduct extends Product {public NullProduct() {this.name null;this.price 0.0;}public String getName() {return name;}public double getPrice() {return price;}
}// 商品工厂类
public class ProductFactory {private static final MapString, Product products new HashMap();static {products.put(product1, new ConcreteProduct(Product 1, 100.0));products.put(product2, new ConcreteProduct(Product 2, 200.0));}public static Product getProduct(String productName) {Product product products.get(productName);if (product ! null) {return product;}return new NullProduct();}
}// 调用代码的类
public class XZ {public static void main(String[] args) {Product product1 ProductFactory.getProduct(product1);System.out.println(product 1 name: product1.getName() , price: product1.getPrice());Product product3 ProductFactory.getProduct(product3);System.out.println(product 3 name: product3.getName() , price: product3.getPrice());}
}4. 类关系图 5. 应用场景
当对象应该具有某些行为但是目前没有能够实现它们时。当一个空值null带来了麻烦并且需要将其替换为默认值。
6. 易错点
确认返回的空对象与需要替代的空值的类型相同。空对象的实现必须符合原接口的规范以确保替代效果正确。
7. 优缺点
优点
避免了空指针异常的出现。可以让代码更具可读性和简洁性。可以避免频繁检查null值引起的代码冗余。
缺点
可能会增加代码的复杂性。创建不必要的对象可能会占用内存空间。
8. 总结
空对象模式是一种非常实用的设计模式可以有效地解决空值的问题并且避免了空指针异常的出现。在项目开发中我们可以根据实际需要使用空对象模式对代码进行优化和重构使之更加健壮、易读和易于维护。 工厂模式与策略模式Factory And Strategy Pattern
1. 工厂模式Factory Pattern
工厂模式是一种创建对象的设计模式。它通过定义一个公共的接口或抽象类并由具体的工厂类来创建对象实例。工厂模式将对象的创建与使用分离客户端只需要与工厂进行交互而无需直接创建对象。
主要特点
定义一个公共的接口或抽象类作为产品的基类。使用具体的工厂类来创建具体的产品实例。客户端通过工厂类获取所需产品的实例。
适用场景
当一个类不知道它所需要的具体对象类型时可以使用工厂模式来创建对象。当一个类希望由其子类来指定创建对象的具体类型时可以使用工厂模式。
2. 策略模式Strategy Pattern
策略模式是一种行为型设计模式它定义了一系列算法并将每个算法封装成单独的类使它们可以相互替换。策略模式使得算法的变化独立于使用算法的客户端。
主要特点
将可变的行为封装成独立的策略类。客户端通过上下文类来选择和使用具体的策略。
适用场景
当一个系统需要在多个算法中选择一种并且希望在运行时可以动态切换算法时可以使用策略模式。当一个类中有多种变化的行为每种行为都可以通过继承或接口来实现时可以使用策略模式。
3. 区别总结Difference Summary
工厂模式是创建型模式关注的是对象的创建过程策略模式是行为型模式关注的是算法的封装和切换。工厂模式通过工厂类来创建对象而策略模式通过上下文类来选择和使用算法。工厂模式强调对象的创建过程和客户端与产品之间的解耦而策略模式强调封装可变的行为并使其可以相互替换。工厂模式一般用于创建对象的场景而策略模式一般用于算法的封装和切换场景。 设计模式拓展Design Mode Expansion
设计模式是一种用于解决特定问题的通用解决方案它们是经过验证的、被广泛接受的最佳实践。除了常见的设计模式还有一些拓展和衍生的设计模式以及一些设计原则和编程技巧可以进一步优化和扩展设计模式的应用。
并发设计模式并发编程中有一些特定的设计模式用于解决多线程和并发访问的问题如锁、信号量、阻塞队列等。函数式编程的设计模式随着函数式编程的兴起也出现了一些与函数式编程相关的设计模式如柯里化、函数组合、惰性求值等。架构模式除了针对具体问题的设计模式还有一些面向整个软件系统架构的设计模式如分层架构、微服务架构等。响应式编程模式响应式编程是一种面向异步数据流和事件驱动的编程范式它在处理事件和数据流时使用了一些特定的设计模式如观察者模式和迭代器模式。数据访问设计模式用于解决数据访问层的设计问题如数据访问对象模式DAO、仓储模式等。
这些拓展和衍生的设计模式都是在特定场景下为了解决特定问题而产生的它们丰富了设计模式的应用范围并提供了更多的解决方案供开发者选择。在实际应用中我们需要根据具体的问题和需求选择合适的设计模式或者结合多种设计模式来构建出更复杂、更灵活的系统。同时也应该注意不要滥用设计模式只有在合适的场景下使用合适的设计模式才能真正发挥它们的优势。 玄子Share 设计模式 GOF 全23种 七大设计原则 9.25