忘川流花 忘川流花
浩淼烟波何处去,东风不再催人愁。
关注数: 101 粉丝数: 63 发帖数: 926 关注贴吧数: 250
架构整洁之道 12-14章读后感 在这一章里,主要介绍的是组件。说起组件,什么是组件呢?这里沿用书中的定义:组件是一种自包含、可重用、可互操作的软件单位,它统一了数据和行为,通常以模块的形式存在,用于构建更大的系统。 对于组件来说,有一个与我们息息相关的词:组件化,这个词一般会跟插件化放在一起被提及,但本质上,组件化他是一种软件开发方法论,它将系统分解为独立可复用的模块(组件)来实现复杂系统的构建。组件化的主要目标是提高项目(或者说系统)的可维护性和可复用性。通过组件化,我们可以将复杂的问题分解为一系列更小、更易于管理和理解的部分。 组件化的优势主要体现在以下几个方面: 1. 提高开发效率:这点是显而易见的,由于组件可以复用,所以可以大大减少开发工作量和开发时间。我们只需要编写一次组件,就可以在多个地方使用,大大提高了开发效率。比如现在项目里的一些卡片ui,当我们进行下沉后会在多个业务场景被使用到,这就是组件化。2. 提高代码质量:这一点可能不会像上面说的提高开发效率那么会给大家直观的感受,但实际上,因为每个组件都是独立的,因此可以单独对组件进行测试和优化,从而提高整个系统的稳定性和性能。组件化使得每个组件都有明确的职责,这样可以降低代码出错的概率,提高代码的质量。这样说来其实有点抽象,举个比较直观的例子:分享功能就是一个组件,对于各个业务方,其实是不关心分享内部实现的,只需要分享组件提供对应的能力就可以了。同样,如果分享出现了问题,也只需要排查组件外和组件内是否存在问题,就可以定位问题的解决方(『甩锅』)3. 提高系统的可维护性:系统由独立的组件构成,每个组件都有明确的接口和职责。当系统需要修改或扩展时,只需要修改或添加相关的组件即可,而不需要改动整个系统。但同样的,其实组件化的缺点页不容忽视: 1. 设计和开发难度增加:组件化需要我们具有较高的抽象能力和设计能力,以确保组件具有良好的复用性和独立性。毕竟能够被抽象出来的功能才是组件,过分定制化让功能无法被其他场景使用,那就称不上组件了。2. 代码管理复杂:由于系统由许多独立的组件构成,所以代码管理(依赖管理等)可能会变得复杂。今天下午其实就遇到了一个很显著的例子 这里有几个公有的成员变量,赋值和引用几乎不可查,我将其调为私有后,添加的set、get方法,结果需要改动足足29处,说来改动其实非常小,但涉及范围过广。 3. 性能损耗:如果组件间的通信过于频繁或者组件的粒度设计得过于细,可能会导致系统性能下降。这个其实页很好理解,因为组件的存在,就需要处理依赖问题,那么一个底层base就必然存在,之前统计过一次通过消息框架打开页面和直接intent打开页面 总的来说,组件和组件化是一种非常有效的软件开发方法,它可以帮助开发者更好地管理复杂系统,提高开发效率和代码质量。但同时,它也不可避免的会导致项目的复杂化。
架构整洁之道7-11 在我们日常开发中,设计原则是一种用来指导设计决策的方法,它帮助开发者构建出高效、可维护、可扩展、可复用的系统。这几章中主要介绍了5种原则: 1. 单一职责原则(Single Responsibility Principle,SRP):它指的是一个类应该只有一个改变的原因。也就是说,一个类应该只负责一个功能领域中的职责。如果一个类负责了多个领域的职责,那么它就可能在一个领域的变化影响到另一个领域,这将使得系统变得复杂且难以维护。遵循这个原则,可以提高类的可读性和可维护性,同时也有利于软件的复用。2. 开放封闭原则(Open-Closed Principle,OCP):它指的是软件实体(类、模块、函数等等)应当对扩展开放,对修改封闭。也就是说,当需要添加新功能时,我们应该尽量通过添加新代码来实现,而不是修改原来的代码。这样可以降低修改代码带来的风险,并提高软件的可维护性。3. 里氏替换原则(Liskov Substitution Principle,LSP):它指的是子类型必须能够替换掉它们的基类型。也就是说,如果一个程序使用了一个基类的对象,那么它也应该能够使用该基类的任何一个子类的对象,而且替换后程序的行为不变。遵循这个原则,可以提高软件的可复用性和可维护性。4. 接口隔离原则(Interface Segregation Principle,ISP):它指的是客户端不应该被迫依赖于它不使用的接口。也就是说,一个类对另一个类的依赖应该建立在最小的接口上。遵循这个原则,可以减少类之间的耦合度,提高系统的灵活性。5. 依赖倒置原则(Dependency Inversion Principle,DIP):它指的是高层模块不应该依赖于低层模块,两者都应该依赖于抽象。也就是说,抽象不应该依赖于细节,细节应该依赖于抽象。遵循这个原则,可以降低类之间的耦合度,提高系统的稳定性。
架构整洁之道3-4 在本书的第三章中提到了一个对于我们来说其实很重要的概念:编程范式,其主要包括:结构化编程,面向对象编程和函数式编程。相对于其他比较宽泛的概念,编程范式其实是我们看待程序的观点,代表了程序设计者认为程序应该如何被构建和执行的看法 结构化编程定义与背景结构化编程,也称为模块化编程,是20世纪60年代末期为了对抗软件危机而提出的一种编程范式。它鼓励程序员使用分而治之的方法,将复杂的程序分解成可管理的小块,每块完成一个具体的任务。关键概念* 模块化: 将程序分解成独立的单元或模块,每个模块实现特定的功能。* 序列结构: 程序按顺序执行代码块。* 选择结构: 使用条件语句决定执行哪个代码块,例如if, else, switch。* 迭代结构: 通过循环重复执行代码块,例如for, while, do-while。 优点:* 可读性强: 通过将问题分解成小的部分来解决,代码更易于理解。* 易于维护: 模块化的代码更容易修改和扩展。* 降低复杂性: 简单的控制结构降低了代码逻辑的复杂性。缺点:* 功能限制: 对于非常复杂或需要高度抽象的系统,结构化编程可能不够用。* 缺乏重用性: 代码重用性不如面向对象编程。面向对象编程(OOP)定义与背景面向对象编程是一种编程范式,它使用“对象”来模拟现实世界中的事物和事物间的交互。对象具有状态(属性)和行为(方法),并且能够模拟真实世界的复杂性。关键概念* 封装: 隐藏对象的内部状态和实现细节,只通过接口与外界交互。* 继承: 允许新创建的类继承现有类的属性和方法。* 多态: 允许不同的对象对同一消息做出不同的响应。 优点:* 代码可重用性: 通过继承机制,可以很容易地复用和扩展现有的代码。* 可扩展性: 新的功能可以通过添加新的对象和类来实现,不必修改现有的代码。* 可维护性: 对象的封装提供了代码的安全性和隐藏性,便于管理和修改。缺点:* 性能问题: 对象创建、继承和多态等都可能带来时间和空间上的开销。* 复杂性: 设计一个良好的面向对象系统需要深刻的设计思考,系统可能会变得复杂。函数式编程(FP)定义与背景函数式编程是一种把计算看作是数学函数的应用,强调无副作用的纯函数。这种范式的根源可以追溯到数学函数,特别是λ演算。关键概念* 不可变性: 数据对象在创建后其状态就不能改变。* 纯函数: 函数的输出值只依赖于输入的参数,不依赖任何外部状态。* 高阶函数: 函数可以接受其他函数作为参数,也可以返回一个函数。 优点:* 可预测性强: 纯函数使得代码易于推理和测试。* 并行编程: 不可变数据和无副作用的特性使得函数式编程非常适合并行处理。* 模块化: 高阶函数和纯函数促进了代码的模块化。缺点:* 资源消耗: 特别是在处理大数据或复杂递归时,函数式编程可能导致内存和性能问题。* 学习曲线: 对于习惯于命令式和面向对象编程的开发者来说,函数式编程的概念可能难以掌握。
代码里的世界观15-16章读后感 在Android开发中,多线程是一个重要的概念,它允许在单个应用程序中同时执行多个任务,从而提高应用程序的性能和响应性。 1. 多线程的定义 * 多线程:指在一个进程中同时执行多个任务的技术。在Android中,多线程技术通常用于执行耗时操作(如网络请求、文件读写等),以避免阻塞主线程(UI线程),从而提高用户体验。 2. 实现多线程的方式 * 使用Thread类:通过继承Thread类或者创建Thread匿名内部类的方式来创建线程对象,并重写run()方法来定义线程执行的操作。 * 使用Runnable接口:通过创建一个实现Runnable接口的类的实例,并将其作为参数传递给Thread类的构造函数来创建线程。这种方式与继承Thread类相比,具有更好的解耦性和扩展性。 * 使用HandlerThread类:HandlerThread是继承自Thread的一个类,它内部封装了一个Looper和Handler,可以方便地实现线程间的通信。它适用于那些需要频繁地与主线程进行交互的场景。 * 使用AsyncTask类:AsyncTask是一个封装了异步操作的类,它可以在后台执行耗时操作,并在主线程更新UI。它简化了线程和Handler的使用,使得异步操作更加简单和方便。 3. 注意事项 * UI更新必须在主线程进行:Android规定,所有与UI相关的操作(如更新UI元素、显示对话框等)都必须在主线程(UI线程)中执行。如果在子线程中直接更新UI,会导致程序崩溃。 * 避免阻塞主线程:网络请求、数据库或者文件I/O等都属于耗时操作,非常容易导致主线程的阻塞造成App卡顿。因此,这些操作应该放在子线程中执行。 * 合理使用线程同步与锁机制:在多线程环境中,为了避免数据竞争和死锁等问题,需要使用合适的同步与锁机制(如synchronized关键字、ReentrantLock等)。 4. 线程池的使用 * 线程池的优点:在Android开发中,频繁地为每一个任务创建一个线程会导致性能下降和内存占用过多。而线程池可以重用线程,避免线程的频繁创建和销毁,从而提高性能并减少内存占用。此外,线程池还可以控制线程的数量,避免过多的线程导致系统资源耗尽。 * Android提供的线程池:Android提供了ThreadPoolExecutor类来管理线程池。开发者可以根据需要创建不同类型的线程池(如固定线程池、缓存线程池等)来满足不同的需求。 * 线程池的优化:在使用线程池时,需要注意合理配置线程池的参数(如核心线程数、最大线程数、队列容量等),以避免线程过多或过少导致的性能问题。此外,还需要定期检查内存泄漏等问题,确保系统的稳定性和性能。
代码里的世界观13-14章读后感 对于我们的日常开发,隐式约定主要涉及到Intent的使用,特别是隐式Intent。那么什么是隐式Intent?隐式Intent是指在启动Activity、Service或BroadcastReceiver时,不直接指定需要激活的组件的名称,而是通过设置action、data和category等属性,让Android系统根据这些属性来匹配并启动最合适的组件。系统通过比较Intent中的action、category和data与AndroidManifest.xml中定义的intent-filter来找到最匹配的组件。 并且Intent中的action必须与intent-filter中的某个action完全匹配(区分大小写)。 对于Intent可以没有category,但如果有,那么每个category都必须与intent-filter中的category匹配。 对于data部分,URI的结构(包括scheme、host、port和path等)也必须与intent-filter中定义的规则相匹配。 隐式Intent的使用场景都有哪些呢?当希望应用之间能够相互调用或共享数据时,可以使用隐式Intent。例如,通过发送一个包含图片数据的隐式Intent,可以请求系统打开能够处理图片的应用。并且隐式Intent也常用于实现自定义的URL Scheme跳转协议,允许通过特定的URL格式来启动应用内的某个Activity。 为了使应用能够响应隐式Intent,开发者需要在AndroidManifest.xml中为相应的组件(如Activity)配置intent-filter。 并且在intent-filter中,可以指定多个action、category和data规则,以便更灵活地匹配不同类型的隐式Intent。
代码里的世界观10-12章读后感 首先提到的是if..else语句,if...else 是编程中常用的条件控制语句,用于在满足某些条件时执行特定的代码块。在项目中使用 if...else 可以帮助我们根据条件来决定程序的执行流程。他的优点是很明显的 1. 明确性:if...else 语句提供了清晰的条件判断逻辑,使得代码易于理解和维护。 2. 灵活性:可以根据不同的条件执行不同的代码块,为程序提供了强大的分支处理能力。 3. 普适性:几乎所有编程语言都支持 if...else 结构,因此它非常通用。 ⚠️注意,使用else if的时候要记得else场景 对于其缺点来说,首先是嵌套复杂性:当 if...else 语句嵌套过多时,代码会变得难以阅读和维护,这种情况通常被称为“箭头形”或“金字塔”代码。并且可扩展性差:随着条件的增加,if...else 语句可能变得非常冗长和复杂,不便于后续的修改和扩展。 那对于这种大量的if..else场景来说,有什么好的结局方式呢? 1. 使用查找表(Lookup Table)或映射(Map): * 对于多个固定的输入和对应的输出,可以使用查找表或映射来代替多个 if...else 语句,从而提高代码的可读性和可维护性。 2. 策略模式: * 策略模式允许在运行时根据上下文选择算法的行为。通过将每个条件分支的逻辑封装到一个独立的类中,可以减少 if...else 的使用,并提高代码的可扩展性。 3. 状态模式: * 当对象的状态改变时,其行为也随之改变。通过将不同状态下的行为封装到独立的类中,可以减少复杂的 if...else 结构。 4. 使用多态: * 如果条件判断涉及到对象的类型,可以使用多态来替代 if...else。通过定义接口和子类,并在子类中实现特定的行为,可以消除类型检查的需要。 5. 简化逻辑: * 仔细检查 if...else 语句中的条件,看是否有冗余或可以简化的部分。有时通过重新组织代码或引入新的变量,可以简化复杂的条件判断。 6. 提取方法: * 将复杂的 if...else 语句块中的代码提取到独立的方法中,这样可以提高代码的可读性和可重用性。 7. 使用switch语句(如果语言支持): * 在某些情况下,使用 switch 语句可能比 if...else 更清晰,尤其是当条件是基于枚举或几个固定的值时。 第二点就是static,对于java来说static声明的变量或方法属于类级别,不需要创建对象就可以直接使用,这提供了全局访问的便利性。并且其在内存中只存在一份,因此可以唯一标识某些状态或数据,便于进行全局状态的管理和共享。由于static成员在类加载时就已经初始化,并且常驻内存,因此调用起来非常快捷方便。但同时,静态方法不能调用非静态的方法和变量,这在一定程度上限制了其灵活性。同时,静态方法中不能使用this和super关键字,因为它不属于任何一个对象实例。并且由于静态成员在程序运行期间一直存在,不会被垃圾回收机制回收,因此会常驻内存。这可能导致不必要的内存占用,特别是当静态成员较大或数量较多时。
代码里的世界观 8-9章读后感 对于java来说,函数(或称为方法)是编程的基础组件,与我们的日常开发是密不可分的,从科学角度上来讲,我们怎样设计函数更科学呢? 首先要说的就是单一职责原则,这个是大家都比较清楚的,既每个函数应该只有一个引起变化的原因,即函数应该只做一件事。如果一个函数承担了过多的功能,那么当需求变化时,这个函数可能需要多处修改,增加了出错的概率。通过将功能拆分到不同的函数中,每个函数只关注一个具体的任务,可以使代码更加清晰、易于维护。 同时,函数的命名应该准确地反映其功能,避免使用过于简单或者含糊不清的名称。好的函数名能够自解释,让阅读代码的人能够迅速理解函数的作用。同时,命名应遵循Java的命名规范,如使用驼峰命名法等。并且函数的参数设计也是关键的一环。应该尽量减少函数的参数数量,以提高函数的可读性。当函数需要多个参数时,可以考虑将这些参数封装到一个对象中传递。同时,参数的命名也要有意义,能够清晰地表达参数的作用。 对于函数的返回值来说,函数的返回值应该与其功能紧密相关。如果函数执行后没有需要返回的结果,那么返回类型应该为void。如果有返回值,应选择合适的返回类型以清晰地表达函数的结果。同时,应避免返回不必要的对象或数据,以减少内存消耗和提高性能。对于函数的异常情况,应充分考虑可能出现的异常情况,并对其进行恰当的处理。对于可能抛出的异常,应在函数签名中明确声明,以便调用者能够捕获并处理这些异常。同时,应避免滥用异常处理机制,将其作为正常的程序流程控制手段。 这里其实还有一点,那就是函数应尽量减少对外部状态的依赖和修改,以降低函数之间的耦合度。避免在函数内部修改全局变量或静态变量的状态,以减少潜在的并发问题和错误。函数应该尽量做到“纯函数”的特性,即相同的输入总是产生相同的输出,且没有可观察的副作用。 为了提高代码的可读性和可维护性,应为每个重要的函数编写详细的文档注释,这点其实在最近大家的代码中,体现比较明显。注释应清晰明了地解释函数的功能、参数、返回值以及可能抛出的异常等信息。同时,代码本身也应具有可读性,通过合理的缩进、空格和换行等排版方式来提高代码的清晰度。
代码里的世界观6-7章读后感 在这两章中,主要讲了Java中,对象之间的关系主要可以分为四种:依赖、关联、聚合和组合。这四种关系在面向对象编程中起着至关重要的作用,它们不仅影响着代码的结构和设计,还直接关系到系统的可扩展性、可维护性以及性能。 1. 依赖关系 定义:依赖关系表示一个类依赖于另一个类的定义。在Java中,这种关系通常体现为局部变量、方法的形参或对静态方法的调用。 优势: * 灵活性:依赖关系允许类之间的松耦合,使得一个类的改变不会过多地影响其他类。 * 易于测试和维护:由于依赖关系较弱,对依赖方的测试和维护相对独立,不会因被依赖方的变化而导致大量的修改工作。 劣势: * 可能的冗余:如果过度使用依赖关系,可能导致代码中存在大量的临时性和偶然性的依赖,增加代码的复杂性。 * 潜在的错误传播:虽然依赖关系较弱,但如果被依赖的类发生错误,这种错误可能会通过依赖关系传播到其他类中。 2. 关联关系 定义:关联关系是类与类之间的联接,它使一个类知道另一个类的属性和方法。关联可以是双向的或单向的,在Java中通常通过成员变量来实现。 优势: * 直接访问:通过关联关系,一个类可以直接访问另一个类的属性和方法,提高了代码的执行效率。 * 代码清晰:明确的关联关系有助于理解类之间的交互和依赖,使代码更加清晰易懂。 劣势: * 紧耦合:与依赖关系相比,关联关系导致类之间的耦合度更高,一个类的改变可能需要同时修改与之关联的类。 * 资源消耗:由于关联关系通常通过成员变量实现,因此会占用更多的内存资源。 3. 聚合关系 定义:聚合关系是关联关系的一种特例,表示整体与部分的关系。在聚合关系中,代表部分的对象有可能会被多个代表整体的对象所共享。 优势: * 重用性:部分对象可以在多个整体对象之间共享,提高了代码的重用性。 * 灵活性:由于部分对象可以独立存在,因此整体对象的构建更加灵活多变。 劣势: * 生命周期管理:在聚合关系中,整体对象不负责管理部分对象的生命周期,这可能导致资源管理的复杂性增加。 * 潜在的错误传播:如果部分对象发生错误,这种错误可能会影响到所有使用该部分对象的整体对象。 4. 组合关系 定义:组合关系是比聚合关系更强的关联关系。它要求代表整体的对象负责代表部分对象的生命周期,组合关系是不能共享的。 优势: * 封装性:组合关系将部分对象完全封装在整体对象内部,提高了代码的封装性和安全性。 * 生命周期管理:整体对象负责管理部分对象的生命周期,简化了资源管理并减少了潜在的内存泄漏问题。 劣势: * 紧耦合:与关联和聚合关系相比,组合关系导致类之间的耦合度更高,增加了代码的复杂性和维护难度。 * 性能开销:由于整体对象需要负责管理部分对象的生命周期,因此可能会带来额外的性能开销。
代码里的世界观 第4-6章读后感 在我们的开发过程中,耦合和解耦是两个至关重要的概念,它们直接关系到我们app的可维护性、可扩展性以及开发效率。 那么,什么称得上是耦合呢?耦合是指两个或多个组件之间的依赖关系。在项目中,这种依赖可能体现在不同模块、类或者方法之间。高耦合的系统往往意味着一个组件的变化会直接影响到其他组件,导致维护成本增加。 常见的耦合类型有哪些呢? * 内容耦合:当一个模块直接使用另一个模块的内部数据或内部结构时,就发生了内容耦合。这是最强的耦合形式,通常应避免。 * 公共耦合:多个模块都访问同一个公共数据环境时发生的耦合。 * 控制耦合:一个模块通过传递开关、标志、名字等控制信息,明显地控制选择另一模块的功能。 * 标记耦合:两个模块之间因为传递数据结构而产生的耦合。 项目中出现了高耦合的问题有什么表现 * 可维护性差:当一个模块需要修改时,高度耦合可能会导致其他模块也需要相应调整,增加维护成本。 * 可扩展性受限:高度耦合的系统难以添加新功能或模块,因为新模块的加入可能会破坏原有的依赖关系。 * 测试困难:高耦合使得单元测试变得复杂,因为模块之间的相互影响使得隔离测试变得困难。 既然谈到了耦合,那与之相关的就是如何解耦。其实消息框架的一个设计思路就是为了解耦 解耦是什么?解耦是降低软件系统中各组件之间依赖关系的过程,目的是提高系统的灵活性、可维护性和可扩展性。 常见的解耦的方法有哪些? * 接口隔离:通过定义清晰的接口来减少类之间的直接依赖。每个类只应该知道自己需要的接口,而不是具体的实现类。 * 依赖注入:通过外部配置或构造函数等方式,将依赖关系从硬编码中抽离出来,使得组件之间的关系更加灵活。 * 事件总线/发布-订阅模式:允许组件之间通过事件进行通信,而不是直接调用对方的方法。 * 使用设计模式:如观察者模式、中介者模式等,可以有效地降低模块间的耦合度。
读代码里的世界观 第一章有感 在我们的日常开发过程中,数据和代码相互依存、相互影响,这里既有着单纯的概念,又有着宏观上的联系。 首先,数据是信息的载体,可以是数字、文字、图像、声音等形式,用于描述事物的状态、属性或行为。在大方向上讲,在计算机科学中,数据通常以二进制的形式存储和处理。而代码则是一系列指令的集合,用于控制计算机硬件执行特定的操作。这些指令通常由编程语言编写,并被编译或解释成机器语言以供计算机执行。 我们最近很多的架构都基于数据驱动代码:例如首页的feed卡片,这里的核心思想是 * 使用数据描述应用状态:数据驱动的核心思想是使用数据来描述应用的状态。这意味着应用程序的各种状态和属性都由数据来表示。 * 数据与界面绑定:在数据驱动的方法中,界面的修改与数据的修改是绑定的。当数据发生变化时,界面会自动更新以反映这些变化。 * 确定的映射关系:应用状态与用户界面之间存在确定的映射关系。这种映射关系确保了只要应用状态发生变化,用户界面就会随之变化。 这里的优势主要体现在: * 提高响应性:由于数据与界面紧密绑定,当数据变化时,界面可以立即作出响应,提高了应用的反应速度。 * 易于测试和维护:由于应用的状态和行为都由数据决定,这使得对应用进行测试和维护变得更加容易。开发者可以更容易地模拟和测试不同的数据状态,从而确保应用的稳定性和可靠性。 随着技术的不断发展,数据与代码之间的关系也在不断变化。以下是一些可能的发展趋势: 1. 数据驱动的开发模式:随着大数据和人工智能技术的普及,数据将越来越多地驱动软件的开发和决策过程。开发者将更多地依赖数据来优化代码和提升用户体验。 2. 代码生成与自动化:随着自动化技术的发展,越来越多的代码将通过自动化工具生成。这些工具可以根据数据和业务需求自动生成高效的代码,从而提高开发效率和质量。 3. 云原生与边缘计算:随着云原生技术和边缘计算的兴起,数据和代码将更加紧密地集成在云端和边缘设备上。这将使得数据的处理更加高效,同时也为实时数据分析和响应提供了可能。 4. 安全与隐私保护:随着数据和代码的重要性日益凸显,它们的安全性和隐私保护也将成为关注的焦点。未来,我们可能会看到更多的加密技术和访问控制机制被应用于数据和代码的保护中。
《设计模式》第六章读后感 本章其实可以理解为是对全书的总结,在日常开发中,设计模式是一种被广泛应用的方法论,它为我们提供了一种解决常见问题的最佳实践。这些经过验证的解决方案,不仅提高了代码的可读性和可维护性,还增强了系统的可扩展性和灵活性。设计模式是软件工程中一种重要的思想,它是对软件设计经验的总结,是其他开发者在长期实践中形成的宝贵财富。 设计模式有助于提升代码的可重用性。在软件开发过程中,经常会遇到一些相似或相同的问题,如果没有设计模式,开发者可能需要每次都从头开始解决问题,这不仅浪费时间,而且容易引入错误。而有了设计模式,开发者可以直接使用已经验证过的解决方案,大大提高了开发效率。例如,工厂模式允许开发者在不指定具体类的情况下创建对象,这使得代码更加灵活,更易于维护和扩展。 同时,设计模式有助于降低代码的耦合度。在复杂的软件系统中,各个组件之间的依赖关系往往错综复杂,这给代码的维护和修改带来了很大的困难。设计模式通过引入抽象层、接口隔离等原则,将系统划分为一系列低耦合、高内聚的模块,使得每个模块都可以独立地进行开发和测试,降低了系统的复杂性。例如,观察者模式允许对象之间建立一对多的依赖关系,当一个对象的状态发生改变时,它的所有依赖者都会收到通知并自动更新,这使得系统更加灵活,更易于适应变化。 此外,设计模式还有助于提高代码的可读性和可理解性。在软件开发中,代码的可读性是非常重要的,它直接影响到代码的可维护性和可扩展性。设计模式通过引入一些通用的命名规范和编程约定,使得代码更加清晰易懂。例如,策略模式允许开发者定义一系列的算法,并将每一个算法封装起来,使得它们可以互相替换,这不仅提高了代码的灵活性,还使得代码更加易于阅读和理解。 并且,设计模式还有助于提升开发者的设计能力。学习和应用设计模式,需要开发者对软件设计原则有深入的理解,对系统的需求有清晰的认识,对可能的变化有充分的预见。通过不断地实践和学习,开发者可以逐渐掌握各种设计模式的精髓,提高自己的设计能力,从而能够设计出更加优秀、更加健壮的软件系统。 设计模式还有助于促进团队之间的交流和协作。在软件开发过程中,团队之间的交流和协作是非常重要的。使用设计模式,可以为团队成员提供一个共同的语言和工具,使得他们能够更加顺畅地交流和协作。当团队成员都熟悉并理解设计模式时,他们可以更加快速地理解彼此的代码和设计思路,减少误解和冲突,提高开发效率。
设计模式第五章读后感(下) 对于第五章后半部分行为型设计模式中主要介绍了:备忘录、观察者、状态、策略、模板方法和访问者这六种行为型设计模式,对于其中的备忘录模式(Memento Pattern)来说,其可以更好的保存和恢复状态,因为备忘录模式允许在不破坏对象封装性的前提下,捕获并保存对象的内部状态,之后可以恢复对象到之前的状态。并且因此跟有灵活性,因为备忘录可以存储对象状态的多个版本,用户可以根据需要选择恢复到哪个版本。并且相对的可以简化操作,对于用户来说,不需要了解对象内部状态的具体实现细节,就可以通过备忘录来恢复对象的状态。但同样的,这个方式也会造成资源消耗的问题,因为如果对象的状态数据很大,保存和恢复状态可能会消耗大量的内存资源。并且具有管理复杂性:需要正确管理备忘录对象的生命周期,以防止内存泄漏或状态恢复错误。也存在安全性问题,因为如果备忘录对象被不恰当地共享或修改,可能会导致对象状态的不一致或损坏。 还有就是提到了观察者模式(Observer Pattern),这个设计模式在目前我们的项目中有较多使用场景,首先,他可以松耦合:观察者和被观察者之间通过抽象接口进行通信,降低了它们之间的耦合度。并且更方便维护一致性,因为当被观察者的状态发生变化时,所有依赖它的观察者都会自动收到通知并更新,保持了系统状态的一致性。还具有相当的可扩展性,因为可以方便地增加新的观察者和被观察者,而不需要修改现有的代码。 但相对的观察者模式也存在一些劣势:首先就是效率问题,如果观察者数量过多或更新频繁,可能会导致系统性能下降。也存在一定的依赖问题,因为观察者和被观察者之间可能存在循环依赖,需要注意设计和实现上的解耦。并且还存在通知顺序问题:观察者之间的更新顺序可能难以控制,有时需要额外的逻辑来管理。 对于状态模式(State Pattern)来说,首先优势就是具有较好的封装性,将对象的行为封装在不同的状态对象中,使得对象的行为更加清晰和易于管理。并且也具有较好的可扩展性,因为可以方便地增加新的状态和转换,而不需要修改使用状态模式的对象。还在一定程度上可以减少条件语句:通过使用状态模式,可以避免在对象中使用大量的条件语句来判断对象的状态。但同样的也会造成类膨胀:如果状态过多,可能会导致产生大量的类,增加系统的复杂性。并且状态转换缺乏可见性因为状态之间的转换可能不够明显,需要额外的文档或注释来解释。而且对于上下文与状态的依赖可能存在问题,因为上下文对象需要知道所有可能的状态,并且需要在状态改变时更新其引用,这增加了上下文与状态之间的依赖。 还有提到的就是策略模式(Strategy Pattern),首先涉及到的就是灵活性,因为策略模式允许在运行时根据需要选择算法或策略,提高了系统的灵活性。并且具有良好的可扩展性,可以方便地增加新的策略,而不需要修改使用策略模式的对象。也可以减少条件语句:通过使用策略模式,可以避免在对象中使用大量的条件语句来选择不同的算法或策略。但同样的会涉及到策略数量问题,因为如果策略数量过多,可能会导致系统难以管理和维护。这里客户端复杂性:客户端需要知道不同的策略以及何时选择合适的策略,这增加了客户端的复杂性。还具有一定的通信开销,因为如果策略之间需要共享数据或状态,可能会增加额外的通信开销。 其中提到了模板方法模式(Template Method Pattern)其具有良好的封装性,按照模板方法模式,会将算法的不变部分封装在父类中,而将可变部分留给子类实现,提高了代码的封装性。并且具有一定的扩展性,因为通过继承父类并重写其抽象方法,可以方便地扩展新的子类而不需要修改父类的代码。对于复用性层面来说,父类中定义的模板方法可以被多个子类共享和复用。但同样的具有继承的局限性:模板方法模式依赖于继承来实现,这可能会导致继承层次过深或子类数量过多的问题。也存在灵活性限制,因为由于父类定义了算法的框架和步骤,子类在实现具体方法时可能受到一定的限制。并且抽象类与接口的依赖存在问题,使用模板方法模式时,需要定义一个抽象类或接口来定义模板方法和抽象方法,这增加了系统的抽象性和复杂性。
设计模式第五章读后感(part1) 在软件开发中,设计模式是解决常见问题的最佳实践。行为型模式特别关注对象之间的通信和职责分配。 对于其中的指责链(责任链)模式来说,他可以更好的解耦:请求发送者和接收者之间的耦合度降低,发送者不需要知道具体由哪个对象处理请求。并且具有灵活性:可以动态地改变链内的成员或者调整它们的顺序,增加或删除处理请求的对象都很方便。对于扩展性方面:新的请求处理类可以很容易地加入到责任链中,而不需要修改现有代码。 但同样,因为充分解耦也会导致出现性能问题:如果责任链过长,或者处理请求的过程复杂,可能会导致性能下降。 容易调试困难:当请求没有得到处理时,不容易找出是哪个环节出了问题,因为请求可能在链中的任何位置被丢弃。 并且不保证请求被处理:如果没有任何对象处理请求,请求就会无声无息地消失,这可能会导致难以发现的错误。 对于命令模式来说同样可以降低耦合度,因为请求发送者和接收者解耦,发送者只需要知道如何发送命令,而不需要知道命令是如何被接收者执行的。 并且对于队列请求:命令对象可以被存储起来,从而实现请求的队列化、撤销和重做等功能。还可以额外的进行日志记录,可以方便地记录请求的历史信息,用于审计或故障排查。 对于他的缺点,他可能会导致复杂性增加:引入命令模式可能会增加系统的复杂性,因为需要定义额外的命令类和接收者类。并且他也可能导致过度设计:在一些简单的场景下,使用命令模式可能过于复杂,没有必要。 而解释器模式来说,首先他具有可扩展性:可以很容易地添加新的解释规则。并且很灵活,可以方便地修改现有规则,以适应语法上的变化。并且很易于实现,对于简单的语法,解释器模式的实现相对简单。 但另一方面,也会容易引入性能问题:对于复杂的语法,解释器模式可能会导致性能下降,因为需要遍历和解析整个语法树。导致项目难以维护:随着语法的复杂性增加,解释器的代码可能会变得难以理解和维护。并且不适用于复杂语法:对于非常复杂的语法,使用专门的解析器生成器(如ANTLR、Bison等)可能更为合适。 对于迭代器模式,在我们的项目中比较容易用到,首先他通过遍历元素的方式,可以顺序访问聚合对象中的各个元素,而不需要暴露该对象的内部表示。还会简化聚合类:聚合类只需要提供一个创建迭代器的接口,而不需要自行处理遍历逻辑。并且具有一致性:提供一致的遍历接口,使得客户端代码可以透明地遍历不同类型的聚合对象。 但同样,会有较大的性能开销:使用迭代器模式可能会引入额外的性能开销,因为需要创建和维护迭代器对象。也可能破坏封装性:如果迭代器提供了对聚合对象内部结构的直接访问,可能会破坏封装性。 对于中介者模式来说其具有降低耦合度:通过引入中介者对象,降低了各个同事对象之间的耦合度,使得它们可以独立地变化和复用。并且可以简化交互:将复杂的交互逻辑集中在中介者对象中,简化了同事对象之间的交互。也比较易于维护:由于交互逻辑被封装在中介者对象中,因此当需要修改交互逻辑时,只需要修改中介者对象即可,而不需要修改多个同事对象。但另一方面中介者可能变得庞大和复杂:如果中介者承担了过多的职责,它可能会变得庞大和难以维护。这违背了“单一职责原则”。也会导致过度集中化:所有的交互都通过中介者进行,可能会导致过度集中化。如果中介者出现故障,整个系统可能会受到影响。并且会限制灵活性:由于所有的交互都由中介者管理,因此可能会限制系统的灵活性。在某些情况下,直接进行交互可能更为简单和高效。 在这一章中,可以感受到我们在实际开发中,应根据具体需求和场景选择合适的模式。同时,也需要注意避免过度使用或误用模式,以免引入不必要的复杂性和开销。
《设计模式》第四章读后感part2 这一章的后半部分主要讲了三个结构型模式:外观模式、享元模式和代理模式 外观模式(Facade Pattern) 外观模式是一种结构型设计模式,它为子系统中的一组接口提供了一个统一的高层接口,使得子系统更容易使用。在日常开发中,这意味着我们可以隐藏复杂的系统细节,只暴露必要的、简化的接口给外部使用。他的优点包括: 1. 简化复杂性:当系统由许多小类或接口组成,且它们之间的关系复杂时,外观模式可以提供一个简单的接口,客户端无需了解底层实现细节。 2. 降低耦合:外观模式将客户端与具体的实现类解耦,使得客户端代码更加灵活,易于维护和修改。 3. 提高开发效率:新加入的开发者可以通过外观模式快速了解和使用系统,而无需深入了解每个组件的具体实现。 享元模式(Flyweight Pattern) 享元模式是一种用于性能优化的结构型设计模式,它主要通过共享对象来减少系统中对象的数量,从而节省内存和提高性能。他的优点包括: 1. 内存优化:在需要创建大量相似或相同对象的情况下,享元模式通过共享对象实例来显著减少内存消耗。 2. 性能提升:由于减少了对象的创建和销毁,系统的性能得到提升,特别是在图形渲染、字符渲染等需要大量小对象的场景中。 3. 状态与行为分离:享元模式强调将对象的内部状态与外部状态(或上下文)分离,使得对象可以在不同的上下文中共享。 代理模式(Proxy Pattern) 代理模式是一种结构型设计模式,它提供了一个代理对象来控制对原始对象的访问。代理模式可以在不修改原始类的情况下增加额外的功能或控制。代理模式的优点是: 1. 访问控制:代理模式可以用于实现访问控制,例如,只有满足特定条件的客户端才能访问原始对象。 2. 性能优化:代理可以在需要时才创建或加载原始对象,这种延迟加载的策略可以提高系统的启动速度并减少资源消耗。 3. 增强功能:通过代理,我们可以在不修改原始类的情况下增加额外的功能,如日志记录、权限检查、事务处理等。 4. 远程访问:在分布式系统中,代理模式常用于实现远程对象的访问。客户端通过代理对象与远程服务器上的对象进行通信,无需直接处理复杂的网络通信细节。 5. 保护原始对象:代理可以保护原始对象免受不必要的或恶意的访问。例如,代理可以限制对敏感数据的访问或防止对原始对象的非法修改。
《设计模式》第四章读后感part1 结构型模式作为设计模式的一大类别,一般主要关注如何将类或对象组合成更大的结构,以提供新的功能或实现特定的行为。一般包括配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式等。这些模式的核心思想是通过组合和继承等方式,将不同的类或对象组合在一起,形成一个更大的、更复杂的结构,以满足特定的需求。作为结构型模式来说,一般通过组合和继承等方式,将不同的类或对象组合在一起,形成一个松耦合的结构。这样,当某个部分发生变化时,不会对整个系统产生太大的影响,从而降低了系统的耦合度,并且通过结构型模式,我们可以将系统划分为多个独立的、可复用的组件。这些组件可以独立地进行修改和扩展,而不需要对整个系统进行重构。这大大提高了代码的可维护性和可扩展性。结构型模式中的许多模式都支持代码的重用。例如,装饰器模式允许我们动态地给对象添加新的功能,而不需要修改其源代码;组合模式允许我们将对象组合成树形结构,以表示“部分-整体”的层次结构,使得我们可以对单个对象和组合对象使用统一的操作。并且结构型模式中的桥接模式、适配器模式等允许我们在不修改现有代码的情况下,引入新的抽象或实现。这使得系统更加灵活,能够更好地应对需求的变化。
读《设计模式》第三章有感part2 单例模式作为创建型模式,如果不正确地实现或使用单例模式,可能会导致内存泄漏问题。这里总结了一些单例模式中常见的内存泄漏问题: 1. 静态实例持有Context引用:在Android开发中,有时会将Activity或其他Context对象传递给单例。如果单例的生命周期比Activity长(通常是这样),那么当Activity应该被销毁时,由于单例仍然持有它的引用,Activity将不会被垃圾回收器回收,从而导致内存泄漏。 2. 注册监听器未注销:单例对象经常用于注册监听器或回调。如果在不再需要时没有注销这些监听器,那么相关的对象(可能是活动、服务或其他组件)将无法被垃圾回收,因为它们仍然被单例间接引用。 3. 使用不恰当的静态内部类:有时,开发者可能会在单例中使用静态内部类来实现延迟初始化。然而,如果静态内部类持有外部类的引用,并且外部类持有大量资源(如Activity上下文),这也可能导致内存泄漏。 4. 线程和异步任务的不当管理:单例对象可能会启动线程或异步任务。如果这些任务在长时间运行后仍然持有单例的引用,或者单例持有这些任务的引用,而这些任务又持有其他资源(如数据库连接、网络连接等),则可能导致资源无法释放和内存泄漏。 5. 长生命周期对象持有短生命周期对象引用:除了Context之外,其他任何短生命周期的对象如果被长生命周期的单例持有引用,都可能导致类似的内存泄漏问题。
读《设计模式》第三章有感part1 创建性模式是设计模式的一大类别,主要关注如何创建对象,隐藏对象创建的具体逻辑,使得代码更加灵活和可复用。创建性模式主要包括工厂模式、抽象工厂模式、单例模式等。这些模式的核心思想是将对象的创建与使用分离,降低系统的耦合度,提高代码的灵活性和可维护性。对于创建性模式来说,一般通过抽象、接口或工厂类等方式,将对象的创建过程与使用过程分离,从而达成解耦的目的,并且通过将对象的创建过程封装在专门的类或方法中,使得代码结构更加清晰,易于阅读和维护。对于单例模式来说,可以通过确保系统中某个类的对象只有一个实例,从而保证了对象的一致性。这在多线程环境或需要共享资源的场景中尤为重要。 有一些比较常见的创建性模式的应用场景,其实在日常的开发过程中经常会使用到: 1. 工厂模式:当需要根据不同的输入或条件创建不同类型的对象时,可以使用工厂模式。例如,在一个日志记录系统中,可能需要根据不同的日志级别创建不同类型的日志记录器。 2. 抽象工厂模式:当需要创建一系列相互关联或依赖的对象时,可以使用抽象工厂模式。例如,在一个图形编辑软件中,可能需要同时创建画笔、画布和颜色等对象。 3. 单例模式:当需要确保系统中某个类的对象只有一个实例时,可以使用单例模式。例如,数据库连接池、线程池等资源池通常都是单例的。 4. 建造者模式:当需要创建一个复杂的对象,且该对象的构建过程包含多个步骤或可变部分时,可以使用建造者模式。例如,创建一个包含多个属性和配置选项的数据库连接对象。 5. 原型模式:当需要创建与现有对象类似的新对象,并且希望避免重新初始化新对象时,可以使用原型模式。例如,在一个包含大量复杂计算结果的对象中,我们可以通过复制现有对象来快速创建新对象,而无需重新进行计算。
《设计模式:可复用面向对象软件的基础》 《设计模式:可复用面向对象软件的基础》第二章读后感 在第二章中,着重通过以例子的方式来指导着我们如何在项目中使用设计模式,并且依此构建更加健壮、可维护和可复用的软件系统。 在本章中,主要通过格式化作为切入段,通过修饰用户界面,作为切入点,5-8章的内容则主要是从:支持多种视感标准,支持多种窗口系统,用户操作以及拼写检查和断字处理这几个角度来介绍。 在这几章的阅读中,其实觉得和之前所学到的“针对接口编程,而不是针对实现编程”这一原则比较相似,接口定义了一种契约,它规定了类应该提供哪些方法,但不关心这些方法的具体实现。通过面向接口编程,我们可以实现代码的高度解耦,使得客户端代码只依赖于接口,而不是具体的实现类。这意味着,即使实现类发生了变化,只要接口保持不变,客户端代码就不需要修改。这种松耦合的设计方式大大提高了软件的可维护性和可扩展性。 对于书中阐述的支持多种视感标准,支持多种窗口系统,我觉得与“开闭原则”这一概念相类似。这一原则要求软件实体对扩展开放,对修改关闭。换言之,我们应该尽量通过添加新代码来扩展系统的功能,而不是通过修改现有代码。这一原则对于保持软件的稳定性和可维护性至关重要。在实际项目中,我们经常会遇到需求变更的情况。如果按照开闭原则进行设计,我们可以在不破坏现有功能的基础上,轻松地添加新功能,从而满足用户的需求。并且同时要关注基类和子类之间的行为兼容性。子类必须能够替换其父类,并且替换后系统的行为保持不变。这一原则确保了继承的正确使用,避免了因为继承而引入的潜在问题。在实际编程中,我们经常会遇到滥用继承的情况。在目前贴吧的旧代码中,经常会出现仅仅为了代码复用而盲目地使用继承,却忽略了继承可能带来的问题。为了支持多种场景固然重要,但在使用继承时,我们也要确保子类能够完全替代父类,并且不会破坏系统的原有行为。
《设计模式》第二章有感 设计模式,作为一种经过反复验证的解决方案,专为解决软件开发中的常见问题而诞生。它们并不是凭空想象出来的,而是众多软件工程师在实际项目中不断试验、总结和完善的结果。第二章中,我们了解到,每一种设计模式都像是一种经过千锤百炼的工具,能够帮助我们更加高效、优雅地解决复杂的问题。 举个例子,在面对一个看似复杂的问题时,如果我们能够识别出它的模式,并应用已经存在的解决方案,那么就可以大大节省时间和精力。这就像是站在巨人的肩膀上,能够看得更远,做得更多。设计模式的复用性不仅提高了软件开发的效率,更保证了软件的质量和稳定性。 除了复用性,设计模式还展现出开放性和封闭性的特质。开放性意味着这些模式可以灵活地组合在一起,形成更加强大的解决方案;而封闭性则意味着每一种设计模式都有其特定的应用场景和边界条件,需要我们在使用时仔细斟酌。这种开放与封闭的平衡,正是设计模式的优点所在。 有时候在面对实际问题时,我们可能会因为无法准确识别出对应的模式而感到困惑。但通过阅读我们应该明显,如何逐渐学会去从不同的角度去看待问题,如何去寻找隐藏在背后的模式。我相信,随着时间的推移和实践的积累,在这样的思考下会更好的使用设计模式。 此外,第二章还提到了设计模式的分类,如创建型、结构型和行为型等。这些分类有助于我们更好地理解和记忆各种设计模式。例如,创建型模式主要关注对象的创建过程,包括工厂方法、抽象工厂等;结构型模式则关注如何将类或对象组合在一起形成更大的结构,如适配器、装饰器等;而行为型模式则关注对象之间的通信和协作方式,如观察者、策略等。
《设计模式》第一章读后感 对于我们的日常开发来说,我们并应该是从怎样完成这个角度作为我们开发工作的出发点,怎样做的更好才是我们真正需要思考和总结的问题。在这样的背景下,设计模式的出现就非常有意义,所谓设计模式,其实就是设计经验,而经验总结,无疑是我们做的更好的一个保证。 在阅读了第一章之后,我深深体会到了设计模式的魅力和价值。它不仅仅是解决问题的一种方式,更是一种思考问题的框架和角度。在错综复杂的软件设计中,如何找出最合适的解决方案成为了每一位开发人员面临的挑战。而设计模式正是为我们提供了一个指南,帮助我们更好地理解和应对这些挑战。 设计模式不仅仅是一种代码实现的方式,更是一种对问题的抽象思考。它让我们能够从一个更高的层次去看待问题,从而更好地把握问题的本质。在面对复杂问题时,我们往往会被细节所困扰,而设计模式则为我们提供了一个清晰的思路,帮助我们抓住问题的核心。 设计模式还强调了复用的重要性。在软件开发中,重复造轮子是不可取的。通过使用设计模式,我们可以一次又一次地使用已经验证过的解决方案,而无需重复劳动。这样不仅可以提高开发效率,还可以减少错误和漏洞的出现。 当然,设计模式并不是万能的。它只是一种工具,如何使用它还需要结合实际情况进行权衡和选择。在实际开发中,我们不能盲目地套用设计模式,而需要根据具体情况进行适当的调整和创新。
1 下一页