当前位置: 首页 > news >正文

amp网站建设百度网盘资源搜索

amp网站建设,百度网盘资源搜索,住房和城乡建设部机关服务中心,网站开发时间表#x1f680; 作者 #xff1a;“码上有前” #x1f680; 文章简介 #xff1a;后端高频面试题 #x1f680; 欢迎小伙伴们 点赞#x1f44d;、收藏⭐、留言#x1f4ac; 往期精彩内容 【后端高频面试题–设计模式上篇】 【后端高频面试题–设计模式下篇】 【后端高频… 作者 “码上有前” 文章简介 后端高频面试题 欢迎小伙伴们 点赞、收藏⭐、留言 往期精彩内容 【后端高频面试题–设计模式上篇】 【后端高频面试题–设计模式下篇】 【后端高频面试题–Linux篇】 【后端高频面试题–Nginx篇】 【后端高频面试题–Mybatis篇】 【后端高频面试题–SpringBoot篇】 什么是设计模式怎么理解设计模式 设计模式是在软件设计中针对常见问题和场景提供的可重用解决方案的一种描述。它们是由经验丰富的软件开发者和设计师总结和归纳出来的旨在解决软件设计中的通用问题并提供经过验证的、可靠的解决方案。 设计模式可以看作是解决常见设计问题的模板或蓝图。它们描述了一种特定问题的解决方案以及如何将不同的组件、类和对象进行组织和交互以达到设计目标。设计模式不是具体的算法或代码实现而是一种更高层次的抽象可以帮助开发者理解和沟通设计思想。 理解设计模式可以从以下几个方面入手 问题和场景设计模式是为了解决特定的问题和应对常见的设计场景而存在的。首先了解具体问题和场景例如如何处理对象之间的依赖、如何实现灵活的扩展性等。 模式的描述每个设计模式都有明确的描述包括该模式的名称、意图、问题描述、解决方案以及涉及的角色和关系。仔细阅读并理解每个模式的描述可以帮助你熟悉其设计思想和解决方案。 具体实现理解设计模式后尝试通过代码实现来加深理解。可以使用适当的编程语言和工具根据模式的描述创建相应的类、接口和对象并演示模式的应用。 实际应用将设计模式应用于实际项目中可以帮助识别和解决类似的问题并提供可重用和可维护的解决方案。通过实际应用可以更好地理解模式的优势、适用性和局限性。 设计模式的学习和理解是一个渐进的过程。开始时可以重点关注一些常用的设计模式如单例模式、工厂模式、观察者模式等。随着经验的积累逐渐熟悉更多的设计模式并学会在实际项目中选择和应用合适的模式。阅读设计模式的经典书籍和参与相关的讨论和实践也是提高理解和应用设计模式的有效途径。 设计模式分类 设计模式可以根据其解决问题的方式和目标进行分类。以下是常见的设计模式分类 创建型模式Creational Patterns这些模式关注如何创建对象以及在不暴露对象创建逻辑的情况下实现对象的实例化。创建型模式包括单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式。 结构型模式Structural Patterns这些模式关注如何将类和对象组合成更大的结构并定义它们之间的关系。结构型模式包括适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式和享元模式。 行为型模式Behavioral Patterns这些模式关注对象之间的通信和交互方式以及如何在系统中分配职责。行为型模式包括策略模式、观察者模式、责任链模式、命令模式、迭代器模式、模板方法模式、访问者模式、备忘录模式、状态模式和中介者模式。 J2EE模式J2EE Patterns这些模式是特定于Java企业版Java Enterprise EditionJ2EE的设计模式用于解决企业级应用程序开发中的常见问题。J2EE模式包括MVC模式、业务代表模式、数据访问对象模式、前端控制器模式、拦截过滤器模式等。 并发模式Concurrency Patterns这些模式关注多线程和并发编程中的问题和解决方案。并发模式包括锁模式、线程池模式、读写锁模式、观察者模式等。 除了以上分类还有其他的设计模式如领域驱动设计模式Domain-Driven Design Patterns、面向切面编程模式Aspect-Oriented Programming Patterns等。 每个设计模式都有其特定的用途和适用场景了解不同类型的设计模式可以帮助开发者在设计和开发过程中选择合适的模式并遵循最佳实践。 设计模式的六大原则 设计模式的六大原则是指在软件设计过程中的准则和指导原则用于帮助开发者设计出可维护、可扩展和可复用的软件系统。这些原则被广泛应用于各种设计模式中。以下是六大原则的简要介绍 单一职责原则Single Responsibility PrincipleSRP一个类应该只有一个引起它变化的原因。换句话说一个类应该只承担一个责任。这样可以提高类的内聚性并使其更加易于理解、修改和测试。 开放封闭原则Open-Closed PrincipleOCP软件实体类、模块、函数等应该对扩展开放对修改关闭。通过使用抽象、接口和多态等机制可以在不修改现有代码的情况下增加新功能或行为。 里氏替换原则Liskov Substitution PrincipleLSP子类型必须能够替换其基类型。这意味着在使用继承关系时子类必须能够替代父类并完全符合其约定。这样可以确保在不破坏原有功能的情况下进行扩展。 依赖倒置原则Dependency Inversion PrincipleDIP高层模块不应该依赖于低层模块两者都应该依赖于抽象。抽象不应该依赖于具体实现细节而是应该依赖于抽象接口。这样可以降低模块之间的耦合度提高代码的灵活性和可维护性。 接口隔离原则Interface Segregation PrincipleISP客户端不应该强迫依赖它们不使用的接口。一个类不应该依赖于它不需要的接口。通过定义细粒度的接口和使用接口隔离可以避免出现臃肿的接口和不必要的依赖关系。 迪米特法则Law of DemeterLoD也称为最少知识原则一个对象应该对其他对象有尽可能少的了解。一个类应该只与其直接的朋友进行通信而不应该了解朋友的内部细节。这样可以减少对象之间的依赖关系提高代码的松耦合性。 这些原则在软件设计中起着重要的指导作用帮助开发者设计出具有良好结构和可维护性的软件系统。然而这些原则并不是绝对的具体实践时需要根据实际情况进行权衡和应用。 单例模式 什么是单例模式 单例模式是一种创建型设计模式它确保一个类只有一个实例并提供全局访问点以获取该实例。单例模式通常用于需要在整个应用程序中共享资源或控制某个独占资源的情况。 理解单例模式可以从以下几个方面入手 唯一实例单例模式要求类只能有一个实例存在。这意味着在任何时候只能创建一个对象并且该对象可以被全局访问。 全局访问点单例模式提供了一个全局访问点通常是一个静态方法通过该方法可以获取单例对象的引用。这样可以确保在应用程序的任何地方都可以方便地访问该对象。 实例化控制单例模式通常涉及对实例化过程的控制以确保只有一个实例被创建。这可以通过限制类的构造函数的访问权限或使用延迟初始化等方式来实现。 下面是一个使用Java实现单例模式的示例 public class Singleton {private static Singleton instance;// 私有构造函数防止外部实例化private Singleton() {}// 全局访问点获取单例对象public static Singleton getInstance() {if (instance null) {// 延迟初始化instance new Singleton();}return instance;} }在上述示例中Singleton类的构造函数被声明为私有的这意味着其他类无法直接实例化该类。通过getInstance()方法获取Singleton类的唯一实例。在第一次调用getInstance()方法时会检查instance变量是否为空如果为空则创建一个新的Singleton对象。在后续调用中直接返回已经创建的实例。 这种实现方式被称为懒汉式单例它在需要时才创建实例。需要注意的是该实现方式在多线程环境下可能会导致并发问题因为多个线程可能同时判断instance为空从而创建多个实例。可以通过加锁或使用双重检查锁定等方式来解决并发问题。 除了懒汉式单例还有饿汉式单例、静态内部类单例等不同的实现方式。每种实现方式都有其适用场景和特点具体选择取决于实际需求和性能考虑。 那些地方用到了单例模式 单例模式在许多应用程序和框架中都得到了广泛应用。以下是一些常见的使用单例模式的场景 配置信息管理单例模式可以用于管理应用程序的配置信息确保在整个应用程序中只有一个配置对象避免重复读取配置文件或数据库的开销。 日志记录器单例模式常用于创建全局的日志记录器以便在应用程序中的任何地方记录日志信息并提供统一的日志管理和访问接口。 数据库连接池单例模式可以用于创建和管理数据库连接池以确保在应用程序中重复使用已经建立的数据库连接提高数据库操作的效率。 缓存管理单例模式适用于管理全局的缓存对象以提供高效的数据缓存和访问机制避免重复创建和销毁缓存对象。 线程池单例模式可以用于创建和管理线程池在应用程序中统一管理线程的创建、调度和销毁提高多线程应用程序的性能和可伸缩性。 GUI应用程序中的窗口管理器单例模式可以用于创建和管理窗口管理器对象确保在应用程序中只有一个窗口管理器负责窗口的创建、关闭、切换等操作。 共享资源管理单例模式可以用于管理共享资源例如打印机池、数据库连接池等以避免资源的重复创建和占用提高资源的利用率。 需要注意的是单例模式应该谨慎使用因为它引入了全局状态和共享状态可能导致代码的复杂性和耦合度增加。在使用单例模式时需要仔细考虑线程安全性、并发访问、延迟初始化等问题并在设计时权衡好使用单例模式的利弊。 单例模式的优缺点 单例模式作为一种设计模式具有以下的优点和缺点 优点 独一无二的实例单例模式保证一个类只有一个实例存在这样可以确保全局只有一个访问点方便其他对象对该实例的访问。 全局访问性通过单例模式可以在应用程序的任何地方访问单例对象方便共享资源和数据。 节约资源单例模式避免了重复创建对象的开销特别是对于那些需要消耗大量资源的对象如数据库连接池、线程池等。 数据共享和一致性在单例模式下多个对象共享同一个实例可以保持数据的一致性避免由于多个实例引起的数据不一致问题。 缺点 难以扩展由于单例模式只允许存在一个实例因此扩展时可能会遇到限制。如果需要创建更多的实例或者变换实例就需要修改单例类的代码。 全局状态由于单例模式引入了全局状态可能会增加代码的复杂性和耦合度使得代码难以测试和维护。 难以调试由于单例模式隐藏了对象的创建和生命周期管理调试过程中可能会遇到困难。 并发访问问题在多线程环境下如果没有合适的同步措施单例模式可能导致并发访问的问题如多个线程同时创建实例、竞争条件等。 对象生命周期延长由于单例模式的实例在整个应用程序生命周期中存在如果实例持有大量资源或有长时间的生命周期可能会导致资源占用和内存泄漏问题。 需要根据具体的应用场景和需求来评估单例模式的适用性权衡其优点和缺点。在使用单例模式时应注意线程安全性、并发访问、延迟初始化等问题并在设计时遵循单一职责原则和依赖倒置原则以确保代码的可维护性和扩展性。 单例模式使用注意事项 在使用单例模式时有一些注意事项需要注意 线程安全性如果在多线程环境下使用单例模式需要确保线程安全性。可以通过使用同步机制如锁、双重检查锁等或使用线程安全的初始化方法如静态内部类来保证线程安全。 延迟初始化有时候单例对象的创建可能会比较耗时或复杂为了避免不必要的开销可以采用延迟初始化的方式来创建单例对象。延迟初始化可以通过在首次访问时创建对象而不是在应用程序启动时立即创建。 序列化和反序列化如果单例类需要支持序列化和反序列化需要特别注意序列化对单例模式的影响。可以通过实现readResolve()方法来保证反序列化时返回单例对象防止通过反序列化创建新的实例。 防止反射攻击单例模式在某些情况下可能会受到反射攻击的威胁。可以通过设置构造函数为私有、在构造函数中进行判断等方式来防止反射实例化。 测试难度由于单例模式引入了全局状态可能会增加代码的复杂性和测试难度。在编写单元测试时需要注意对单例对象的模拟和隔离以确保可靠的测试覆盖。 可扩展性和耦合度单例模式可能会限制类的扩展性因为它只允许一个实例存在。如果将来需要创建更多的实例或变换实例可能需要修改单例类的代码。此外单例模式引入了全局状态可能会增加代码的耦合度使得代码难以维护和扩展。 合理使用单例模式应该谨慎使用只在确实需要全局唯一实例的场景下使用。滥用单例模式可能会导致代码的复杂性增加、可维护性下降等问题。 在使用单例模式时需要综合考虑以上注意事项并根据具体的应用场景和需求来评估单例模式的适用性。确保理解单例模式的优缺点并在设计时遵循设计原则以提高代码的可维护性、扩展性和安全性。 单例防止反射漏洞攻击 在某些情况下单例模式可以用于防止反射漏洞攻击。反射漏洞攻击是指攻击者利用反射机制来修改或绕过程序的原本逻辑从而执行恶意代码或获取非授权的访问权限。 通过合理设计单例模式可以增加对反射漏洞攻击的防护。以下是一些常见的防护方法 私有构造函数单例类的构造函数应该设置为私有这样可以防止外部通过反射机制直接调用构造函数创建新的实例。 防止反射实例化在单例类的构造函数中可以增加逻辑判断如果已经存在实例则抛出异常防止通过反射强制创建新的实例。 序列化和反序列化控制如果单例类需要支持序列化和反序列化可以通过实现readResolve()方法确保在反序列化时返回单例对象防止通过反序列化创建新的实例。 需要注意的是单纯依靠单例模式并不能完全防止反射漏洞攻击。攻击者可能采用其他方法来绕过单例模式的限制。为了更有效地防止反射漏洞攻击还应结合其他安全措施如输入验证、安全编码实践、访问控制等。 单例创建方式 在实现单例模式时有多种方式可以创建单例对象。以下是几种常见的单例创建方式 饿汉式Eager Initialization public class Singleton {private static final Singleton instance new Singleton();private Singleton() {// 私有构造函数}public static Singleton getInstance() {return instance;} }这种方式在类加载时就创建了单例对象因此是线程安全的。但它可能会导致不必要的资源浪费因为单例对象的创建是提前进行的。 懒汉式Lazy Initialization public class Singleton {private static Singleton instance;private Singleton() {// 私有构造函数}public static synchronized Singleton getInstance() {if (instance null) {instance new Singleton();}return instance;} }这种方式在首次访问时才创建单例对象延迟了对象的初始化。但它在多线程环境下需要添加同步机制来保证线程安全。 双重检查锁Double-Checked Locking public class Singleton {private volatile static Singleton instance;private Singleton() {// 私有构造函数}public static Singleton getInstance() {if (instance null) {synchronized (Singleton.class) {if (instance null) {instance new Singleton();}}}return instance;} }这种方式在首次访问时进行双重检查避免了每次都进行同步操作提高了性能。使用volatile关键字修饰instance变量可以确保多线程环境下的可见性。 静态内部类Static Inner Class public class Singleton {private Singleton() {// 私有构造函数}private static class SingletonHolder {private static final Singleton instance new Singleton();}public static Singleton getInstance() {return SingletonHolder.instance;} }这种方式利用了类的初始化锁机制通过静态内部类的方式延迟加载单例对象。它既保证了线程安全性又延迟了单例对象的创建。 以上是一些常见的单例创建方式每种方式都有其优缺点和适用场景。在选择单例创建方式时需要根据具体需求、线程安全性要求和性能考虑做出合适的选择。 如何选择单例创建方式 选择单例创建方式时需要考虑以下几个因素 线程安全性如果应用程序在多线程环境下使用单例对象确保线程安全是非常重要的。某些创建方式如饿汉式在类加载时就创建了单例对象因此是线程安全的。其他方式如懒汉式、双重检查锁可能需要添加同步机制来保证线程安全。 延迟初始化如果单例对象的创建比较耗时或复杂可以考虑延迟初始化的方式。懒汉式和静态内部类方式都支持延迟初始化在首次访问时才创建单例对象。 性能考虑某些创建方式可能会引入额外的同步开销影响性能。例如懒汉式使用了同步机制来保证线程安全性可能会影响并发性能。双重检查锁方式通过双重检查来避免每次都进行同步操作提高了性能。 序列化支持如果单例对象需要支持序列化和反序列化操作需要特别注意选择支持序列化的创建方式。静态内部类方式是一个常见的选择因为静态内部类不会被序列化可以确保在反序列化时返回单例对象。 反射攻击防护如果希望防止反射攻击需要选择一种不容易被反射实例化的创建方式。例如在构造函数中增加逻辑判断如果已经存在实例则抛出异常。 代码清晰度和可读性选择创建方式时也需要考虑代码的清晰度和可读性。一些方式可能会引入更多的代码复杂性使得代码难以理解和维护。选择简洁、清晰的方式有助于提高代码的可读性。 综合考虑以上因素选择适合应用程序需求的单例创建方式。根据具体情况可以进行性能测试和评估以确保选择的方式满足应用程序的需求并在性能、线程安全和可维护性之间做出合理的权衡。 工厂模式 怎么理解工厂模式 工厂模式是一种创建型设计模式旨在提供一种统一的方式来创建对象而无需直接暴露对象的具体创建逻辑。它将对象的实例化过程封装在工厂类中客户端只需通过工厂类来请求创建对象而无需直接与具体的对象类交互。 工厂模式主要包含以下几个角色 抽象产品Abstract Product定义了产品的接口或抽象类描述了产品的共同特性和行为。所有具体产品类都必须实现或继承抽象产品。 具体产品Concrete Product实现了抽象产品接口或继承了抽象产品类是工厂模式中真正被创建的对象。 抽象工厂Abstract Factory定义了创建产品的接口声明了创建产品的抽象方法。它可以是接口或抽象类可以包含多个用于创建不同产品的方法。 具体工厂Concrete Factory实现了抽象工厂接口负责创建具体产品的对象。它根据客户端的请求选择合适的具体产品进行实例化。 工厂模式的核心思想是将对象的创建与使用分离客户端只需要依赖于抽象工厂和抽象产品而不需要直接依赖于具体的产品类。这样可以实现代码的解耦提高代码的灵活性和可维护性。通过工厂模式可以轻松地扩展或替换具体产品的实现而无需修改客户端代码。 工厂模式适用于以下情况 当需要创建一组相关的对象时可以使用工厂模式来统一管理对象的创建过程提供一致的接口。 当对象的创建逻辑比较复杂涉及到多个步骤或依赖关系时可以使用工厂模式来封装这些复杂的创建过程。 当希望通过扩展或替换具体产品的实现来实现灵活性时可以使用工厂模式。 总而言之工厂模式通过将对象的创建封装在工厂类中实现了对象创建与使用的解耦提供了一种简洁、灵活的对象创建方式。它是一种常用的设计模式可以在软件开发中提高代码的可扩展性、可维护性和可测试性。 工厂模式分类 工厂模式可以根据其实现方式和结构特点进行分类。以下是几种常见的工厂模式分类 简单工厂模式Simple Factory Pattern简单工厂模式又称为静态工厂模式它由一个工厂类负责创建不同类型的对象。客户端通过向工厂类传递参数来请求创建不同的产品对象。这种模式的特点是工厂类负责所有产品的创建逻辑客户端只需与工厂类交互而无需直接与具体产品类交互。但简单工厂模式违背了开闭原则当需要添加新的产品时需要修改工厂类的代码。 工厂方法模式Factory Method Pattern工厂方法模式使用抽象工厂接口来定义创建对象的方法具体的对象创建由实现该接口的具体工厂类来完成。每个具体工厂类负责创建特定类型的产品对象。工厂方法模式通过将对象的创建延迟到具体工厂类实现了对扩展开放、对修改关闭。客户端通过与抽象工厂接口交互可以根据需要选择具体的工厂类创建对象。 抽象工厂模式Abstract Factory Pattern抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口而无需指定具体的类。它包含一个抽象工厂接口和多个具体工厂类每个具体工厂类负责创建某一类产品。抽象工厂模式适用于需要创建一组相关对象的场景它可以保证创建的对象之间具有一致性而无需关心具体的实现细节。 生成器模式Builder Pattern生成器模式将一个复杂对象的构建过程分解为多个简单的步骤并提供一个指导者Director来按照特定的顺序调用生成器Builder的方法来构建对象。生成器模式主要关注对象的构建过程而不同于工厂模式那样直接返回最终构建好的对象。生成器模式适用于创建复杂对象且构建过程需要多个步骤或者有不同的实现方式的情况。 这些工厂模式都有各自的特点和适用场景选择合适的工厂模式取决于具体的需求和设计目标。 工厂模式优缺点 工厂模式具有以下优点 封装了对象的创建逻辑工厂模式通过将对象的创建逻辑封装在工厂类中使得客户端无需关心具体的创建过程只需通过工厂类来请求创建对象。这样可以提高代码的灵活性和可维护性减少了客户端与具体产品之间的依赖关系。 提供了一致的接口工厂模式定义了一致的接口来创建对象使得客户端可以统一使用抽象工厂和抽象产品而无需直接与具体产品类交互。这样可以降低代码的耦合度便于扩展和替换具体产品的实现。 支持扩展性工厂模式通过抽象工厂和抽象产品的定义可以轻松地扩展新的具体工厂和产品类。在需要添加新的产品时只需创建相应的具体产品和具体工厂并实现工厂接口而无需修改现有的代码。 降低了代码重复如果多个地方需要创建相同类型的对象使用工厂模式可以避免重复的创建代码。通过工厂类集中管理对象的创建逻辑可以提高代码的复用性。 工厂模式也有一些缺点 增加了类的数量引入工厂模式会增加额外的类包括抽象工厂、具体工厂和具体产品类。如果只有少量的产品需要创建使用工厂模式可能会增加代码的复杂性。 需要理解和维护额外的代码工厂模式引入了额外的抽象层和接口需要理解和维护这些额外的代码结构。这可能会增加开发和维护的工作量。 不适合简单的对象创建工厂模式主要适用于对象创建过程比较复杂、涉及多个步骤或依赖关系的情况。对于简单的对象创建使用工厂模式可能会显得繁琐和不必要。 总体而言工厂模式是一种常用的设计模式可以提供一种统一的对象创建方式封装了对象的创建逻辑提高了代码的灵活性和可维护性。但在使用工厂模式时需要权衡其优缺点根据具体的需求和情况做出合理的选择。 为什么要学习工厂设计模式 学习工厂设计模式有以下几个重要的原因 提高代码的可维护性和可扩展性工厂模式可以将对象的创建逻辑封装在工厂类中使得客户端与具体产品类解耦提高了代码的可维护性。当需要添加新的产品时只需创建相应的具体产品和具体工厂并实现工厂接口而无需修改现有的代码。这样可以降低代码的耦合度便于扩展和修改。 代码重用和一致性工厂模式可以集中管理对象的创建逻辑避免在多个地方重复编写创建代码。通过使用工厂类来创建对象可以保持代码的一致性提高代码的复用性。 简化复杂对象的创建过程某些对象的创建过程可能比较复杂涉及多个步骤或依赖关系。工厂模式可以将这些复杂的创建过程封装在工厂类中使得客户端可以简单地通过工厂类来请求创建对象而无需关心具体的创建细节。 符合面向对象设计原则工厂模式符合面向对象设计的开闭原则Open-Closed Principle即对扩展开放对修改关闭。通过使用工厂模式可以通过扩展具体工厂和产品类来添加新的功能而无需修改现有的代码。 增加设计模式的理解和应用能力工厂模式是一种常用的设计模式在实际的软件开发中经常会遇到。学习工厂模式可以增加对设计模式的理解和应用能力使得我们能够更好地理解和使用其他设计模式。 总而言之学习工厂设计模式可以提高代码的可维护性和可扩展性简化复杂对象的创建过程增加代码的重用性和一致性。它是一种常用且重要的设计模式在软件开发中具有广泛的应用。 Spring开发中的工厂设计模式 在Spring开发中工厂设计模式主要体现在以下两个方面 Spring Bean工厂Spring框架提供了一个Bean工厂Bean Factory作为对象的创建和管理中心。Bean工厂负责创建、配置和管理应用中的对象Bean它将对象的创建逻辑封装在内部客户端只需要通过Bean工厂获取需要的对象而无需直接与具体的对象类交互。Spring Bean工厂使用了工厂模式的思想将对象的创建与使用解耦提供了一种统一的对象创建方式。常见的Spring Bean工厂实现包括XML配置的ClassPathXmlApplicationContext、注解配置的AnnotationConfigApplicationContext等。 Spring工厂方法模式在Spring中可以使用工厂方法模式Factory Method Pattern来创建和管理对象。工厂方法模式通过定义一个工厂接口该接口包含用于创建对象的方法具体的对象创建由实现该接口的具体工厂类来完成。Spring中的BeanFactory接口就是一个典型的工厂方法模式的应用它定义了获取Bean的方法具体的Bean创建由不同的实现类如XmlBeanFactory、DefaultListableBeanFactory等来完成。通过工厂方法模式Spring可以根据配置文件或注解等方式动态地创建和管理对象实现了对象的可配置和可扩展。 工厂设计模式在Spring开发中的应用可以提供灵活的对象创建和管理方式降低代码的耦合度提高代码的可维护性和可扩展性。Spring的IoCInversion of Control容器利用工厂设计模式实现了对象的创建和依赖注入使得开发者能够专注于业务逻辑的实现而无需过多关注对象的创建和管理过程。 简单工厂模式 简单工厂模式Simple Factory Pattern也被称为静态工厂模式是一种创建型设计模式它通过一个工厂类根据客户端的请求创建不同的产品对象。客户端无需直接实例化具体的产品类而是通过工厂类来创建所需的产品。 以下是一个使用Java代码示例演示了简单工厂模式的实现 首先我们定义抽象产品接口和具体产品类 // 抽象产品接口 public interface Button {void render(); }// 具体产品类A public class WindowsButton implements Button {Overridepublic void render() {System.out.println(Rendering a button in Windows style.);} }// 具体产品类B public class MacOSButton implements Button {Overridepublic void render() {System.out.println(Rendering a button in macOS style.);} }然后我们创建一个简单工厂类用于根据客户端的请求创建具体产品对象 // 简单工厂类 public class ButtonFactory {public static Button createButton(String type) {if (type.equalsIgnoreCase(Windows)) {return new WindowsButton();} else if (type.equalsIgnoreCase(MacOS)) {return new MacOSButton();} else {throw new IllegalArgumentException(Invalid button type.);}} }最后我们可以编写客户端代码来使用简单工厂模式 public class Client {public static void main(String[] args) {// 使用简单工厂创建Windows风格的按钮Button windowsButton ButtonFactory.createButton(Windows);// 渲染按钮windowsButton.render();// 使用简单工厂创建macOS风格的按钮Button macOSButton ButtonFactory.createButton(MacOS);// 渲染按钮macOSButton.render();} }运行以上代码输出结果如下 Rendering a button in Windows style. Rendering a button in macOS style.在这个示例中简单工厂类ButtonFactory根据客户端传入的类型参数“Windows或MacOS”创建相应的具体产品对象WindowsButton或MacOSButton。客户端代码通过调用简单工厂类的静态方法createButton()来获取所需的产品对象并使用产品对象的方法来实现相应的功能。 简单工厂模式的优点包括 客户端代码与具体产品类解耦客户端只需要依赖于工厂类。可以通过修改工厂类的代码来创建不同的产品对象而无需修改客户端代码。简化了对象的创建过程客户端只需要提供合法的类型参数即可获取相应的产品对象。 然而简单工厂模式的缺点是当需要新增或修改产品时需要修改工厂类的代码违反了开闭原则。 简单工厂模式适用于以下情况 客户端只需要获取产品对象无需关心具体的创建细节。只有少量具体产品类不需要频繁地添加或修改产品。 通过简单工厂模式我们可以实现对象的统一创建和管理提高代码的可维护性和可扩展性。 工厂方法模式 工厂方法模式Factory Method Pattern是一种创建型设计模式它定义了一个创建对象的接口但将具体对象的创建延迟到子类中进行。这样客户端代码通过与抽象工厂接口进行交互而无需关心具体的产品类。 以下是一个使用Java代码示例演示了工厂方法模式的实现 首先我们定义抽象产品接口和具体产品类 // 抽象产品接口 public interface Button {void render(); }// 具体产品类A public class WindowsButton implements Button {Overridepublic void render() {System.out.println(Rendering a button in Windows style.);} }// 具体产品类B public class MacOSButton implements Button {Overridepublic void render() {System.out.println(Rendering a button in macOS style.);} }接下来我们定义抽象工厂接口和具体工厂类 // 抽象工厂接口 public interface GUIFactory {Button createButton(); }// 具体工厂类A用于创建Windows风格的产品 public class WindowsFactory implements GUIFactory {Overridepublic Button createButton() {return new WindowsButton();} }// 具体工厂类B用于创建macOS风格的产品 public class MacOSFactory implements GUIFactory {Overridepublic Button createButton() {return new MacOSButton();} }最后我们可以编写客户端代码来使用工厂方法模式 public class Client {public static void main(String[] args) {// 创建Windows风格的工厂GUIFactory windowsFactory new WindowsFactory();// 使用工厂创建按钮Button windowsButton windowsFactory.createButton();// 渲染按钮windowsButton.render();// 创建macOS风格的工厂GUIFactory macOSFactory new MacOSFactory();// 使用工厂创建按钮Button macOSButton macOSFactory.createButton();// 渲染按钮macOSButton.render();} }运行以上代码输出结果如下 Rendering a button in Windows style. Rendering a button in macOS style.在这个示例中工厂方法模式通过抽象工厂接口GUIFactory定义了创建按钮的方法createButton()具体工厂类WindowsFactory和MacOSFactory分别实现了该接口并负责创建相应风格的按钮。客户端代码通过与抽象工厂接口进行交互调用工厂方法来创建按钮对象并使用按钮对象的方法来实现相应的功能。 工厂方法模式的优点包括 客户端代码与具体产品类解耦客户端只需要依赖于抽象工厂接口。可以通过定义新的具体工厂类来扩展产品族增加新的产品类型而无需修改现有的代码。符合开闭原则对修改关闭、对扩展开放。 工厂方法模式适用于以下情况 客户端代码需要与多个相关的产品对象进行交互但无需关心具体的产品类。需要在运行时动态决定创建哪个具体产品对象。需要扩展产品族时只需添加新的具体工厂和具体产品类无需修改现有的代码。 通过工厂方法模式我们可以实现更灵活、可扩展的对象创建方式提高代码的可维护性和可扩展性。 代理模式 怎么理解代理模式 代理模式Proxy Pattern是一种结构型设计模式它允许通过代理对象控制对真实对象的访问。代理对象充当了客户端和真实对象之间的中介客户端通过代理对象来间接访问真实对象从而可以在访问前后进行一些额外的操作。 代理模式通常涉及三个角色 抽象主题Subject定义了真实主题和代理主题之间的共同接口客户端通过该接口来访问真实主题和代理主题。 真实主题Real Subject定义了真正的业务逻辑是代理模式中所关注的核心对象。 代理主题Proxy Subject实现了抽象主题接口持有一个真实主题的引用充当了客户端和真实主题之间的中介。代理主题可以在访问真实主题前后进行一些额外的操作例如权限验证、缓存、延迟加载等。 代理模式的理解可以从以下几个方面入手 控制访问代理模式允许代理对象控制对真实对象的访问。代理对象可以在访问真实对象之前进行一些准备工作例如权限验证、资源分配等也可以在访问真实对象之后进行一些收尾工作例如日志记录、缓存更新等。通过代理对象的控制可以对真实对象的访问进行灵活的管理。 隔离复杂性代理模式可以将复杂的业务逻辑封装在代理对象中使得客户端不需要关心真实对象的复杂性。客户端只需要与代理对象进行交互代理对象负责处理真实对象的创建、销毁、维护等操作将复杂性隔离在代理对象中简化了客户端的代码。 延迟加载代理模式可以支持延迟加载也称为懒加载。当客户端需要访问真实对象时代理对象可以根据需要动态地创建真实对象并将其初始化。这种延迟加载的方式可以提高系统的性能和资源利用率特别是在真实对象的创建和初始化过程比较耗时或资源密集的情况下。 安全性增强代理模式可以增强系统的安全性。代理对象可以充当一个安全层对真实对象的访问进行控制和限制例如进行身份验证、访问权限验证等。通过代理对象的安全性增强可以保护真实对象免受非法访问和潜在风险。 总之代理模式通过引入代理对象来控制对真实对象的访问并在访问前后进行一些额外的操作从而增强了系统的灵活性、安全性和性能。它可以应用于各种场景例如远程代理、虚拟代理、缓存代理、保护代理等以满足不同的需求。 代理模式应用场景 代理模式可以应用于多种场景以下是一些常见的应用场景 远程代理Remote Proxy当真实对象存在于远程服务器上时客户端无法直接访问真实对象而是通过代理对象与远程服务器进行通信。代理对象负责处理网络通信、数据传输等细节隐藏了远程调用的复杂性使得客户端可以像访问本地对象一样访问远程对象。 虚拟代理Virtual Proxy当真实对象的创建和初始化过程比较耗时时可以使用虚拟代理延迟加载真实对象。代理对象在客户端需要访问真实对象时先创建一个占位符对象等到真正需要使用真实对象时再进行加载和初始化。这样可以避免不必要的开销提高系统性能。 安全代理Security Proxy代理对象可以充当一个安全层对真实对象的访问进行控制和限制。代理对象可以进行身份验证、访问权限验证等操作确保只有经过授权的客户端可以访问真实对象增强系统的安全性。 缓存代理Caching Proxy代理对象可以缓存真实对象的结果以提供快速访问。当客户端请求相同的操作时代理对象可以直接返回缓存的结果避免了每次都重新执行真实对象的操作提高了系统的响应速度和性能。 日志记录Logging代理对象可以在访问真实对象前后进行日志记录用于跟踪和调试系统的运行情况。代理对象可以记录请求的参数、执行时间、返回结果等信息帮助开发人员进行错误排查和性能优化。 延迟加载Lazy Initialization代理对象可以延迟加载真实对象只有在真正需要使用真实对象时才进行创建和初始化。这种延迟加载的方式可以节省系统资源并提高系统的启动速度。 需要注意的是代理模式并不是适用于所有情况的通用解决方案应根据具体的需求和情况来判断是否使用代理模式。在使用代理模式时需要权衡代理对象的引入对系统的复杂性、性能等方面的影响并确保代理模式能够带来实际的好处和价值。 代理模式的分类 代理模式可以根据代理对象的创建方式和使用方式进行分类。以下是代理模式的几种常见分类 静态代理Static Proxy在静态代理中代理对象在编译时就已经确定并且代理对象和真实对象实现相同的接口或继承相同的父类。静态代理需要为每个真实对象创建一个对应的代理对象并在代理对象中调用真实对象的方法。静态代理的优点是简单易懂缺点是需要为每个真实对象创建代理对象导致类的数量增加。 动态代理Dynamic Proxy在动态代理中代理对象是在运行时动态生成的不需要为每个真实对象创建一个对应的代理对象。Java中的动态代理机制是通过反射实现的可以动态地在运行时创建代理对象从而在代理对象中调用真实对象的方法。动态代理的优点是可以减少代理对象的数量缺点是相对于静态代理会增加一些复杂性。 远程代理Remote Proxy远程代理用于在不同的地址空间中代表真实对象通过网络通信的方式进行访问。客户端通过远程代理对象与远程服务器进行通信代理对象负责处理网络通信、数据传输等细节。远程代理可以隐藏真实对象的具体实现细节使得客户端可以像访问本地对象一样访问远程对象。 虚拟代理Virtual Proxy虚拟代理用于延迟加载真实对象也称为懒加载。当客户端需要访问真实对象时虚拟代理会先创建一个占位符对象等到真正需要使用真实对象时才进行加载和初始化。虚拟代理可以避免不必要的开销提高系统性能。 缓存代理Caching Proxy缓存代理用于缓存真实对象的结果以提供快速访问。代理对象会在第一次访问真实对象后将结果缓存起来当客户端再次请求相同的操作时代理对象可以直接返回缓存的结果避免了每次都重新执行真实对象的操作提高了系统的响应速度和性能。 安全代理Security Proxy安全代理用于控制对真实对象的访问权限。代理对象可以进行身份验证、访问权限验证等操作确保只有经过授权的客户端可以访问真实对象增强系统的安全性。 这些分类并不是互斥的实际上一个代理模式可能同时具有多种分类的特点。根据具体的需求和情况可以选择合适的代理模式来实现系统的功能和要求。 三种代理的区别 在代理模式中常见的三种代理类型是静态代理、动态代理和远程代理。它们之间的区别主要体现在以下几个方面 创建方式 静态代理在编译时期就已经创建好代理对象代理对象和真实对象实现相同的接口或继承相同的父类。动态代理在运行时动态生成代理对象不需要为每个真实对象创建一个对应的代理对象。代理对象是根据接口动态生成的利用反射机制实现。远程代理用于在不同的地址空间中代表真实对象通过网络通信的方式进行访问。 对象关系 静态代理代理对象和真实对象之间的关系是一对一的关系每个真实对象都需要对应一个代理对象。动态代理代理对象和真实对象之间的关系是一对多的关系可以为多个真实对象共享一个代理对象。远程代理代理对象和真实对象之间的关系是一对多的关系代理对象可以代理多个真实对象这些真实对象可以位于不同的地址空间。 实现机制 静态代理在编译时期就已经确定代理对象和真实对象的关系代理对象直接调用真实对象的方法。动态代理在运行时动态生成代理对象代理对象通过反射机制调用真实对象的方法。Java中的动态代理机制主要是通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。远程代理代理对象通过网络通信的方式与真实对象进行交互代理对象负责处理网络通信、数据传输等细节。 应用场景 静态代理适用于在编译时期就已经确定代理对象和真实对象的关系且代理对象的数量有限的情况。动态代理适用于在运行时动态生成代理对象的情况可以减少代理对象的数量提高代码的灵活性。远程代理适用于真实对象存在于远程服务器上需要通过网络通信进行访问的情况。 总之静态代理在编译时期确定代理对象动态代理在运行时动态生成代理对象远程代理用于访问存在于远程服务器上的真实对象。选择适当的代理类型取决于具体的需求和场景。 使用代码演示上述三种代理 下面我将使用Java代码为您演示静态代理、动态代理和远程代理的示例。 静态代理示例 // 定义接口 interface Image {void display(); }// 定义真实对象 class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename filename;loadFromDisk();}private void loadFromDisk() {System.out.println(Loading image: filename);}public void display() {System.out.println(Displaying image: filename);} }// 定义代理对象 class ImageProxy implements Image {private RealImage realImage;private String filename;public ImageProxy(String filename) {this.filename filename;}public void display() {if (realImage null) {realImage new RealImage(filename);}realImage.display();} }// 使用示例 public class StaticProxyExample {public static void main(String[] args) {Image image new ImageProxy(image.jpg);// 第一次调用会创建真实对象image.display();// 第二次调用直接使用缓存的真实对象image.display();} }动态代理示例 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;// 定义接口 interface Image {void display(); }// 定义真实对象 class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename filename;loadFromDisk();}private void loadFromDisk() {System.out.println(Loading image: filename);}public void display() {System.out.println(Displaying image: filename);} }// 定义动态代理处理器 class ImageProxyHandler implements InvocationHandler {private Object realObject;public ImageProxyHandler(Object realObject) {this.realObject realObject;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result null;// 在调用真实对象方法之前可以进行相关操作System.out.println(Before displaying image);result method.invoke(realObject, args);// 在调用真实对象方法之后可以进行相关操作System.out.println(After displaying image);return result;} }// 使用示例 public class DynamicProxyExample {public static void main(String[] args) {Image realImage new RealImage(image.jpg);Image imageProxy (Image) Proxy.newProxyInstance(realImage.getClass().getClassLoader(),realImage.getClass().getInterfaces(),new ImageProxyHandler(realImage));imageProxy.display();} }远程代理示例 // 定义接口 interface Image {void display(); }// 定义远程代理对象 class RemoteImageProxy implements Image {private String imageUrl;public RemoteImageProxy(String imageUrl) {this.imageUrl imageUrl;}public void display() {// 在此处实现远程调用逻辑例如通过网络获取图片并进行展示System.out.println(Displaying remote image: imageUrl);} }// 使用示例 public class RemoteProxyExample {public static void main(String[] args) {Image image new RemoteImageProxy(https://example.com/image.jpg);image.display();} }请注意这些示例只是为了演示代理模式的不同类型并可能存在简化。在实际应用中可能需要更复杂的实现例如添加更多的逻辑和错误处理。 建造者模式 怎么理解建造者模式 建造者模式Builder Pattern是一种创建型设计模式它的主要目的是将一个复杂对象的构建过程与其表示分离使得同样的构建过程可以创建不同的表示。 理解建造者模式可以从以下几个方面入手 分离构建过程和表示 建造者模式将一个复杂对象的构建过程拆分成多个步骤每个步骤由一个具体的建造者负责完成。这样就可以将构建过程和最终的对象表示分离开来。通过定义统一的构建接口客户端代码可以灵活地指定构建过程中的步骤顺序从而创建不同的表示。 组装复杂对象 建造者模式通过一系列的构建步骤来逐步构建复杂对象。每个具体的建造者负责实现一个或多个构建步骤将最终结果保存在一个产品对象中。通过组合不同的构建步骤可以创建不同的对象表示而且构建过程可以灵活地扩展和修改。 隔离客户端和具体构建过程 建造者模式将复杂对象的构建过程封装在具体的建造者类中客户端只需关注如何指定构建的步骤和顺序而不需要了解具体的构建细节。这样可以降低客户端代码与具体构建过程的耦合度使得客户端更加简洁和易于维护。 创建不同的表示 建造者模式通过不同的具体建造者来创建不同的对象表示。每个具体建造者实现自己的构建步骤可以根据需要创建不同的对象。通过使用不同的建造者可以以统一的方式构建出不同的对象而无需改变客户端代码。 总之建造者模式通过将复杂对象的构建过程和表示分离使得构建过程灵活可扩展同时隔离了客户端和具体构建过程的耦合。这种模式适用于需要创建复杂对象并且对象的构建过程可能存在多个步骤、变化较大或者需要灵活组装的情况。 建造者模式的分类 建造者模式可以根据实现方式的不同进行分类。常见的分类包括以下两种 静态建造者模式Static Builder Pattern 静态建造者模式是建造者模式的一种变体它使用静态方法来创建和配置复杂对象。在静态建造者模式中通常将建造者方法定义为静态方法通过链式调用来配置对象的属性和参数最后调用一个静态的构建方法来获取最终的对象实例。这种方式可以简化客户端代码的编写并且在链式调用中提供了一种流畅的语法。 动态建造者模式Dynamic Builder Pattern 动态建造者模式是建造者模式的另一种变体它使用动态方法链来创建和配置复杂对象。在动态建造者模式中建造者类通常使用方法链的方式来设置对象的属性和参数每个方法都返回建造者对象本身以便可以连续地进行方法调用。最后调用一个构建方法来获取最终的对象实例。这种方式的优点是可以在运行时动态地配置对象的属性和参数更加灵活。 无论是静态建造者模式还是动态建造者模式它们都遵循了建造者模式的基本原则即将复杂对象的构建过程与其表示分离并提供一种灵活的方式来创建不同的对象表示。具体选择哪种方式取决于项目的需求和设计偏好。 当谈到建造者模式时还有一些相关的概念和要点可以进一步了解 产品Product 产品是由建造者模式创建的复杂对象。产品类通常包含多个属性和方法用于描述和操作该对象的特征和行为。 建造者Builder 建造者是一个接口或抽象类定义了构建复杂对象的各个步骤和方法。建造者通常包含一系列的方法用于设置对象的属性和参数。 具体建造者Concrete Builder 具体建造者是实现了建造者接口的具体类。每个具体建造者负责实现构建过程中的具体步骤和方法。它持有一个产品对象并将最终的结果保存在产品中。 指挥者Director 指挥者是负责使用建造者对象构建复杂对象的类。它定义了一个构建方法该方法接收一个建造者对象作为参数并按照一定的步骤和顺序调用建造者的方法来构建对象。指挥者可以控制和管理构建过程。 客户端Client 客户端是使用建造者模式的代码。客户端通常通过实例化一个具体建造者对象并将其传递给指挥者来构建复杂对象。客户端可以根据需要选择不同的建造者和配置选项从而创建不同的对象。 可选步骤Optional Steps 在建造者模式中某些步骤可能是可选的即客户端可以选择性地调用或不调用这些步骤。建造者模式允许客户端根据实际需求来定制构建过程从而创建不同配置的对象。 建造者模式与工厂模式的区别 建造者模式和工厂模式都是创建型设计模式但它们的关注点不同。工厂模式关注于创建对象它通过一个工厂类来封装对象的创建过程并返回一个已经创建好的对象。而建造者模式关注于构建复杂对象它将构建过程拆分成多个步骤并通过建造者类来逐步构建对象最后返回一个构建好的对象。 建造者模式在实际应用中常用于创建复杂的对象特别是当对象具有多个可选的属性或参数并且构建过程可能存在多个步骤和变化时。它可以提供一种灵活的方式来创建不同配置的对象并将构建过程与表示分离使代码更加清晰、可维护和可扩展。 建造者模式的应用场景 建造者模式适用于以下场景 创建复杂对象 当需要创建的对象具有复杂的内部结构包含多个属性或参数并且构建过程涉及多个步骤和变化时建造者模式可以提供一种有效的方式来构建该对象。 隔离构建过程和表示 如果希望将对象的构建过程与最终的表示分离开来使得构建过程可以独立地扩展和变化建造者模式是一种常用的设计模式。 创建不同配置的对象 当需要创建多个配置不同的对象而且这些对象的构建过程有一定的相似性时可以使用建造者模式。通过使用不同的具体建造者来配置对象的不同属性和参数可以灵活地创建不同的对象。 避免重叠构造函数 如果一个类存在多个构造函数而且构造函数的参数组合较多导致构造函数的数量庞大且难以维护可以考虑使用建造者模式。通过将构造函数的参数转移到建造者类中并使用链式调用的方式来设置参数可以简化构造函数的定义和使用。 创建不可变对象 当需要创建不可变对象时建造者模式可以很好地支持。通过将对象的属性和参数设置为只读并在建造过程中逐步构建对象最后返回一个不可变的对象实例。 创建对象的过程需要细粒度控制 当需要对对象的构建过程进行细粒度的控制和管理时建造者模式可以提供一种灵活的方式。通过在指挥者中定义构建过程的步骤和顺序可以精确地控制对象的创建过程。 总之建造者模式适用于需要创建复杂对象且构建过程与表示分离、可扩展和灵活的情况。它可以提供一种清晰、可维护和可扩展的方式来创建不同配置的对象。 代码演示 当使用建造者模式时通常需要定义产品类、建造者接口或抽象类、具体建造者类和指挥者类。以下是一个简单的代码示例演示了如何使用建造者模式来构建一个电脑对象。 首先定义产品类 Computer class Computer:def __init__(self):self.cpu Noneself.memory Noneself.storage Nonedef set_cpu(self, cpu):self.cpu cpudef set_memory(self, memory):self.memory memorydef set_storage(self, storage):self.storage storagedef display(self):print(Computer configuration:)print(CPU:, self.cpu)print(Memory:, self.memory)print(Storage:, self.storage)然后定义建造者接口 ComputerBuilder from abc import ABC, abstractmethodclass ComputerBuilder(ABC):abstractmethoddef build_cpu(self):passabstractmethoddef build_memory(self):passabstractmethoddef build_storage(self):passabstractmethoddef get_computer(self):pass接下来实现具体建造者类 DesktopBuilder 和 LaptopBuilder class DesktopBuilder(ComputerBuilder):def __init__(self):self.computer Computer()def build_cpu(self):self.computer.set_cpu(Intel Core i7)def build_memory(self):self.computer.set_memory(16GB DDR4)def build_storage(self):self.computer.set_storage(1TB HDD)def get_computer(self):return self.computerclass LaptopBuilder(ComputerBuilder):def __init__(self):self.computer Computer()def build_cpu(self):self.computer.set_cpu(Intel Core i5)def build_memory(self):self.computer.set_memory(8GB DDR4)def build_storage(self):self.computer.set_storage(512GB SSD)def get_computer(self):return self.computer最后定义指挥者类 Director负责控制建造过程 class Director:def __init__(self, builder):self.builder builderdef construct_computer(self):self.builder.build_cpu()self.builder.build_memory()self.builder.build_storage()def get_computer(self):return self.builder.get_computer()现在我们可以使用建造者模式来构建具体的电脑对象 desktop_builder DesktopBuilder() director Director(desktop_builder) director.construct_computer() desktop_computer director.get_computer() desktop_computer.display()laptop_builder LaptopBuilder() director Director(laptop_builder) director.construct_computer() laptop_computer director.get_computer() laptop_computer.display()输出结果 Computer configuration: CPU: Intel Core i7 Memory: 16GB DDR4 Storage: 1TB HDDComputer configuration: CPU: Intel Core i5 Memory: 8GB DDR4 Storage: 512GB SSD以上示例展示了如何使用建造者模式来构建不同配置的电脑对象。通过定义产品类、建造者接口和具体建造者类并由指挥者控制建造过程我们可以灵活地创建具有不同配置的电脑对象。这种方式使得构建过程与表示分离并提供了可扩展和灵活的创建方式。 祝大家新年快乐学业有成万事如意 嘿嘿都看到这里啦乖乖 点个赞吧
文章转载自:
http://www.morning.rlcqx.cn.gov.cn.rlcqx.cn
http://www.morning.nrpp.cn.gov.cn.nrpp.cn
http://www.morning.hjsrl.cn.gov.cn.hjsrl.cn
http://www.morning.rpjr.cn.gov.cn.rpjr.cn
http://www.morning.nrftd.cn.gov.cn.nrftd.cn
http://www.morning.bnxnq.cn.gov.cn.bnxnq.cn
http://www.morning.tstkr.cn.gov.cn.tstkr.cn
http://www.morning.gwdkg.cn.gov.cn.gwdkg.cn
http://www.morning.tdmgs.cn.gov.cn.tdmgs.cn
http://www.morning.wcft.cn.gov.cn.wcft.cn
http://www.morning.hrhwn.cn.gov.cn.hrhwn.cn
http://www.morning.rxsgk.cn.gov.cn.rxsgk.cn
http://www.morning.qnzgr.cn.gov.cn.qnzgr.cn
http://www.morning.spfh.cn.gov.cn.spfh.cn
http://www.morning.czgfn.cn.gov.cn.czgfn.cn
http://www.morning.bxrqf.cn.gov.cn.bxrqf.cn
http://www.morning.knwry.cn.gov.cn.knwry.cn
http://www.morning.lbxcc.cn.gov.cn.lbxcc.cn
http://www.morning.rmppf.cn.gov.cn.rmppf.cn
http://www.morning.fesiy.com.gov.cn.fesiy.com
http://www.morning.kfhm.cn.gov.cn.kfhm.cn
http://www.morning.nytgk.cn.gov.cn.nytgk.cn
http://www.morning.knqck.cn.gov.cn.knqck.cn
http://www.morning.hlkxb.cn.gov.cn.hlkxb.cn
http://www.morning.jqkjr.cn.gov.cn.jqkjr.cn
http://www.morning.yrpd.cn.gov.cn.yrpd.cn
http://www.morning.gbljq.cn.gov.cn.gbljq.cn
http://www.morning.xbzfz.cn.gov.cn.xbzfz.cn
http://www.morning.pdtjj.cn.gov.cn.pdtjj.cn
http://www.morning.nzkkh.cn.gov.cn.nzkkh.cn
http://www.morning.csgwd.cn.gov.cn.csgwd.cn
http://www.morning.rlnm.cn.gov.cn.rlnm.cn
http://www.morning.mtgnd.cn.gov.cn.mtgnd.cn
http://www.morning.ykqbs.cn.gov.cn.ykqbs.cn
http://www.morning.qbfs.cn.gov.cn.qbfs.cn
http://www.morning.hryhq.cn.gov.cn.hryhq.cn
http://www.morning.txmkx.cn.gov.cn.txmkx.cn
http://www.morning.kgrwh.cn.gov.cn.kgrwh.cn
http://www.morning.qrsrs.cn.gov.cn.qrsrs.cn
http://www.morning.gwxsk.cn.gov.cn.gwxsk.cn
http://www.morning.snmsq.cn.gov.cn.snmsq.cn
http://www.morning.dqbpf.cn.gov.cn.dqbpf.cn
http://www.morning.tzkrh.cn.gov.cn.tzkrh.cn
http://www.morning.rxwnc.cn.gov.cn.rxwnc.cn
http://www.morning.qhmql.cn.gov.cn.qhmql.cn
http://www.morning.hxwrs.cn.gov.cn.hxwrs.cn
http://www.morning.dlrsjc.com.gov.cn.dlrsjc.com
http://www.morning.knzmb.cn.gov.cn.knzmb.cn
http://www.morning.dzrcj.cn.gov.cn.dzrcj.cn
http://www.morning.nwcgj.cn.gov.cn.nwcgj.cn
http://www.morning.bkqdg.cn.gov.cn.bkqdg.cn
http://www.morning.llthz.cn.gov.cn.llthz.cn
http://www.morning.skpdg.cn.gov.cn.skpdg.cn
http://www.morning.zfzgp.cn.gov.cn.zfzgp.cn
http://www.morning.nzxdz.cn.gov.cn.nzxdz.cn
http://www.morning.rqkk.cn.gov.cn.rqkk.cn
http://www.morning.hwtb.cn.gov.cn.hwtb.cn
http://www.morning.knswz.cn.gov.cn.knswz.cn
http://www.morning.tfwg.cn.gov.cn.tfwg.cn
http://www.morning.rnds.cn.gov.cn.rnds.cn
http://www.morning.rgpy.cn.gov.cn.rgpy.cn
http://www.morning.dqdss.cn.gov.cn.dqdss.cn
http://www.morning.hxxwq.cn.gov.cn.hxxwq.cn
http://www.morning.frpb.cn.gov.cn.frpb.cn
http://www.morning.deupp.com.gov.cn.deupp.com
http://www.morning.kyfrl.cn.gov.cn.kyfrl.cn
http://www.morning.ljngm.cn.gov.cn.ljngm.cn
http://www.morning.cgstn.cn.gov.cn.cgstn.cn
http://www.morning.lczxm.cn.gov.cn.lczxm.cn
http://www.morning.szoptic.com.gov.cn.szoptic.com
http://www.morning.mdnnz.cn.gov.cn.mdnnz.cn
http://www.morning.rbmm.cn.gov.cn.rbmm.cn
http://www.morning.xjpnq.cn.gov.cn.xjpnq.cn
http://www.morning.zyytn.cn.gov.cn.zyytn.cn
http://www.morning.fjntg.cn.gov.cn.fjntg.cn
http://www.morning.nxkyr.cn.gov.cn.nxkyr.cn
http://www.morning.tgts.cn.gov.cn.tgts.cn
http://www.morning.qllcm.cn.gov.cn.qllcm.cn
http://www.morning.yjknk.cn.gov.cn.yjknk.cn
http://www.morning.kxmyj.cn.gov.cn.kxmyj.cn
http://www.tj-hxxt.cn/news/249106.html

相关文章:

  • 备案的网站名称能重复备案吗把手机网站做成app
  • 女人与马做受网站怎么样把自己的产品网上推广
  • 网站建设基本范例网站模板 兼容
  • 免费网站建设服务山东郓城住房和城乡建设厅网站
  • wordpress国内视频网站吗抽奖网站怎么制作
  • 网站开发app开发免费给我推广
  • 网站域名哪里买厦门建设局人员名单
  • 做网站找模版好吗不属于网络营销的推广手段是什么
  • wap网站生成茂名免费自助建站模板
  • 动漫视频网站模板寻找网站建设 网站外包
  • 四川省建设厅资格注册中心网站青岛做网站公司
  • 简单的个人主页网站制作百度网站域名注册
  • 千度网站建设银行成都市第九支行 网站
  • 可以打开的wap网站龙华网站制作公司
  • asp做的网站怎么运行做评测系统网站首先要干嘛
  • 休闲吧网站建设如果修改wordpress后台登录域名
  • wordpress获取文章中的图片不显示优化网站界面的工具
  • 上海网站搭建公司动漫主题WordPress
  • 国外做论坛网站上海科技网络公司
  • 自建网站和第三方平台国外购物网站排行榜
  • 企业网站制作建设的框架有哪几种长沙网络科技有限公司有哪些
  • 峨眉山移动网站建设搭建网站软件
  • 网站设计外包协议房地产微网站模板
  • 国内搜索引擎网站文化传媒网站建设
  • 龙岩做网站哪家好校园推广的方式有哪些
  • ps做网站分辨率自适应公众号开发助手
  • 怎吗做网站挣钱视频网站开发防止盗链
  • 做网站优化的关键词怎么设置网站掉权重是怎么回事
  • 网站免费源码大全无用下载微信登录界面
  • 一站式网站建设业务有没有教做网站实例视频