💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
>[success] > **所谓的抽象,就是将一系列事物共有的特质提取出来,舍去独有的部分的过程** > **也可以说是指从具体问题中,提取出具有共性的模式,再使用通用的解决方法加以处理** ## 通俗的理解抽象 大家从小到大学到的大部分知识,无一例外的都是将具体事物抽象出来的结果 例如大家学到的 1+1 = 2 这个概念,如何理解和抽象的关系? 一只鸡加一只鸡等于两只鸡,一只狗加一只狗就是两只狗 **这个过程中,共有的特质就是一个实体加另一个实体,就等于了两个实体,独有特质就是一个是猫,一个是狗。** 于是加法了概念就这样诞生,在你理解了这个概念后,就可以灵活应用,比如你就会知道一个人加一个人就等于两个人 而学习知识最好的办法就是将抽象的知识类比为具体的事物来学习,比如老师教你们1+1 = 2 这个概念,是不是就是举的例子,一只鸡加一只鸡等于两只鸡这样? **而我们在应用学习到的知识时候,也是这个道理,先将具体问题抽象为我们所储备的知识,再用知识去解决问题** 一个车可以座5人,10个车能做几人?我们要解决这个问题,得先把问题转为我们学过的数学乘法,在计算出结果 ## 抽象和编程的关系 看到这里你应该对抽象有了一定的理解,那么抽象和编程有什么关系? >[success] > 一个软件的架构写的如何,包括拓展性,可维护性,可移植性等等方面几乎直接由程序开发者对事物的抽象能力来决定,他们能根据项目的需要总结出什么地方需要用什么算法,什么数据结构,什么设计模式等等。 > 大家所熟知的各类设计模式,数据结构,算法,就是对各种情况抽象出来的结果。 所以各位应该知道为什么学习这些知识如此重要。 >[success] > > Thinkphp框架的源码就是不错的典范,不少朋友说是仿的 laravel,这里抛开框架整体思想不说,仅讨论代码的规范和各种设计思想,十分是值得大家学习 **为什么要抽象** > 代码可复用性强,表现为同样的功能,绝不写第二次,没有重复功能的代码 参考 Thinkphp源码里 `think\File `类的 `getInfo `方法,写好后其他地方只管调用即可 > 代码可移植性强,写好的功能可以把代码提出来拿到其他项目里用,没有耦合(关于耦合的概念看文档的‘耦合于解耦’篇)参考Thinkphp源码里的` vender\topthink\think-image`能,使用composer安装,即便拿到其他框架一样可以工作,不会依赖 Thinkphp源码里的任何类库或者函数 **抽象的原则及如何抽象** 抽象需要对计算过程进行观察,看哪些计算模式是固定的,哪些是经常变化的,将共有的部分提取出来封装。 > 通常在抽象时需要遵循一个‘**三次原则**’ 通俗的说,在编写项目过程中,当一个重复的功能出现在三次以上的地方时候,就应该考虑将共有的部分封装为函数或者类,在需要用到的地方调用,不同的部分用传参数的方式传进去 > 第一次用到某个功能时,你写一个特定的解决方法; > 第二次又用到的时候,你拷贝上一次的代码; > 第三次出现的时候,你才着手"抽象化",写出通用的解决方法。 ### 理由 > (1)省事。如果一种功能只有一到两个地方会用到,就不需要在"抽象化"上面耗费时间了。 > (2)容易发现模式。"抽象化"需要找到问题的模式,问题出现的场合越多,就越容易看出模式,从而可以更准确地"抽象化"。 > (3)防止过度冗余。如果一种功能同时有多个实现,管理起来非常麻烦,修改的时候需要修改多处。在实际工作中,重复实现最多可以容忍出现一次,再多就无法接受了。 >[warning] > 当然,面对一些能预知的通用功能,应该先封装好,在进行封装,后面在调用,比如类似排序函数之类的功能等 **通常封装的形式粒度由小到大** > 1. **函数和类中的方法** : 参考thinkphp源码里 `helper.php` 里的函数 > 2. **类** : 包括工具类,机制类等等,参考thinkphp源码里 thinkphp 命名空间下的各个类文件,session,url等等 > 3. **类库** : 功能比较庞大,一个类封装不了的时候,可以考虑封装为多个类,各司其职,相互调用完成复杂逻辑,类似phpexcel,phpMail这样大型工具库,可以参考thinkphp源码里` think\cache` 文件夹下的各个类 >[success] > 经验丰富的程序设计者,总是可以判断出做出什么程度的抽象是合适的 **面向对象中的抽象类 abstract** 如何理解面向对象中的抽象类(abstract) 参考thinkphp源码里` think\cache` 文件夹下的各个类文件 你会发现有个Driver.php里面有个`abstract class Driver`,有好几个方法如` has,get,set`等都是没有方法体,前面用了 `abstract`修饰。再看`driver`文件夹下有很多文件,这些类文件继承了`Driver`,他们每个类都重写了`Driver`类里的用`abstract`修饰过的方法,在这里就是对缓存这个动作做了抽象的结果。 >[success] > **共有特质**:不论用何种方式缓存,`File,Memcache,Redis`等等,必然都有个`set,get,clear`等一些方法 > **独有特质**:每个方式写入数据的方式都不一样,参考每个继承了`Driver`的类,如`File,Memcache`等,他们重写的方法体里就是具体的逻辑 > >[success] > **另外,这个设计思想是典型的适配器模式 > 同样的示例参考 `namespace think\db\connector` 下各个类文件和 `namespace think\db `下的`Connection`类之间的关系**