• 设计原则与思想:面向对象


    目录

    lenson:1 什么是面向对象?

    lesson 2:四大特性分别可以解决哪些编程问题?

    1.封装

    2.抽象

    3.继承

    4.多态

    lenson3:面向对象比面向过程有哪些优势?

    lesson 4:面向对象变成面向过程

    lesson 5:接口和抽象类区别

    lesson 6:为什么要基于接口而非实现编程?


    lenson:1 什么是面向对象?

    关键问题:

    1. 什么是面向对象编程? 将类或者对象作为组织代码的基本单元,并将封装、抽象、继承、多态四个特性,作为代码设计和实现的基石。
    2. 面向对象分析和面向对象设计区别?  面向对象分析就是要搞清楚做什么,面向对象设计就是要清楚怎么做,两个阶段最终的产出是类的设计,包括程序被拆解为哪些类,每个类有哪些属性方法、类与类之间如何交互等。

    扩展:UML相关的,无需多记,需要使用的时候打开:

    Algorithms4/designpattern/pic at master · gdhucoder/Algorithms4 · GitHub

     lesson 2:四大特性分别可以解决哪些编程问题?

    1.封装

            封装也叫做隐藏或者数据访问保护,类通过暴露有限的访问接口,授权外部能够通过类提供的方式来访问内部信息或者数据。

    2.抽象

            抽象将的是如何隐藏方法的具体实现,让调用者只要关心提供方法提供了哪些功能,并不需要知道这些功能是如何实现的。

    3.继承

            继承是用来表示类之间的is-a关系。

    4.多态

            多态是指子类可以替换父类,在实际的代码运行过程中,调用子类的方法实现。

            多态可以提高代码的可扩展性和复用性。

    lenson3:面向对象比面向过程有哪些优势?

    1.什么是面向过程编程与面向对象编程语言?

            面向对象:a.面向对象是一种编程范式或编程风格,它以类或对象作为组织代码的基本单元,并将封装、抽象、继承、多态四个特性,作为代码设计和实现的基石。

                              b.面向对象编程语言是支持类或对象的语法机制,并有现成的语法机制,能方便地实现面向对象编程四大特性。

           面向过程:a.面向过程也是一种编程范式或编程风格,它以过程(方法、函数、操作)作为组织代码的基本单元,以数据(成员变量、属性)与方法分离为最主要的特点。面向过程风格是一种流程化的编程风格,通过拼接一组顺序执行的方法来操作数据完成一项功能。

                            b.最大特点是不支持类和对象两个语法概念,不支持丰富的面向对象编程特性(继承、多态、封装),仅支持面向过程编程。

    2.面向对象编程比面向过程编程有哪些优势?

    a.OOP更加能够应对大规模复杂程序的开发

    b.OOP风格代码更易复用、易扩展、易维护

    首先,我们先来看下封装特性。封装特性是面向对象编程相比于面向过程编程的一个最基本的区别,因为它基于的是面向对象编程中最基本的类的概念。面向对象编程通过类这种组织代码的方式,将数据和方法绑定在一起,通过访问权限控制,只允许外部调用者通过类暴露的有限方法访问数据,而不会像面向过程编程那样,数据可以被任意方法随意修改。因此,面向对象编程提供的封装特性更有利于提高代码的易维护性。

    其次,我们再来看下抽象特性。我们知道,函数本身就是一种抽象,它隐藏了具体的实现。我们在使用函数的时候,只需要了解函数具有什么功能,而不需要了解它是怎么实现的。从这一点上,不管面向过程编程还是是面向对象编程,都支持抽象特性。不过,面向对象编程还提供了其他抽象特性的实现方式。这些实现方式是面向过程编程所不具备的,比如基于接口实现的抽象。基于接口的抽象,可以让我们在不改变原有实现的情况下,轻松替换新的实现逻辑,提高了代码的可扩展性。

    再次,我们来看下继承特性。继承特性是面向对象编程相比于面向过程编程所特有的两个特性之一(另一个是多态)。如果两个类有一些相同的属性和方法,我们就可以将这些相同的代码,抽取到父类中,让两个子类继承父类。这样两个子类也就可以重用父类中的代码,避免了代码重复写多遍,提高了代码的复用性。

    最后,我们来看下多态特性。基于这个特性,我们在需要修改一个功能实现的时候,可以通过实现一个新的子类的方式,在子类中重写原来的功能逻辑,用子类替换父类。在实际的代码运行过程中,调用子类新的功能逻辑,而不是在原有代码上做修改。这就遵从了“对修改关闭、对扩展开放”的设计原则,提高代码的扩展性。除此之外,利用多态特性,不同的类对象可以传递给相同的方法,执行不同的代码逻辑,提高了代码的复用性。

    c.OOP语言更加人性化、更加高级、更加智能

    lesson 4:面向对象变成面向过程

    1.滥用getter、setter方法

    2.滥用全局变量和全局方法

    3.定义数据和方法分离的类

    4.为什么容易写出面向过程风格代码?

            面向对象编程风格正好相反。它是一种自底向上的思考方式。它不是先去按照执行流程来分解任务,而是将任务翻译成一个一个的小的模块(也就是类),设计类之间的交互,最后按照流程将类组装起来,完成整个任务。

    lesson 5:接口和抽象类区别

    抽象的特性:

            1.抽象类不允许被实例化,只能被继承。

            2.抽象类可以包含属性和方法。方法既可以包含代码实现,也可以不包含代码实现。不包含代码实现的叫做抽象方法

            3.子类继承抽象类,必须实现抽象类中的抽象方法。

    接口特性:

            1.接口不能包含属性

            2.接口只能声明方法,方法不能包含代码实现

            3.类实现接口的时候,必须实现接口中声明的所有方法

    如何决定使用抽象类还是接口类?

            如果我们要表示一种is-a关系,并且是为了解决代码复用的问题,我们就使用抽象类;如果我们要表示一种has-a关系,并且是为了解决抽象而非代码复用问题,那么我们就可以使用接口。

            从类的继承层次上来看,抽象类是一种自下而上的设计思路,先有子类的代码重复,然后再抽象成上层的父类。而接口正好相反,它是一种自上而下的设计思路。我们在编程的时候,一般都是先设计接口,再考虑具体实现。

    lesson 6:为什么要基于接口而非实现编程?

    1.越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性,越能应对未来需求变化。好的代码设计,不仅能应对当下的需求,而且在将来需求发生变化的时候,仍然能够在不破坏原有代码设计的情况下灵活应对。

    2.如何基于接口编程?

            a.函数命名不能暴露任何实现细节(接口类)。

            b.封装具体的实现细节(实现类),和每个类相关的类,需要private属性

            c.为实现类定义抽象的接口,具体的实现类都依赖统一的接口定义,遵从一致的上传功能协议。或者依赖接口,而不是具体的实现类来编程。

    1. public interface ImageStore {
    2. String upload(Image image, String bucketName);
    3. Image download(String url);
    4. }
    5. public class AliyunImageStore implements ImageStore {
    6. //...省略属性、构造函数等...
    7. public String upload(Image image, String bucketName) {
    8. createBucketIfNotExisting(bucketName);
    9. String accessToken = generateAccessToken();
    10. //...上传图片到阿里云...
    11. //...返回图片在阿里云上的地址(url)...
    12. }
    13. public Image download(String url) {
    14. String accessToken = generateAccessToken();
    15. //...从阿里云下载图片...
    16. }
    17. private void createBucketIfNotExisting(String bucketName) {
    18. // ...创建bucket...
    19. // ...失败会抛出异常..
    20. }
    21. private String generateAccessToken() {
    22. // ...根据accesskey/secrectkey等生成access token
    23. }
    24. }
    25. // 上传下载流程改变:私有云不需要支持access token
    26. public class PrivateImageStore implements ImageStore {
    27. public String upload(Image image, String bucketName) {
    28. createBucketIfNotExisting(bucketName);
    29. //...上传图片到私有云...
    30. //...返回图片的url...
    31. }
    32. public Image download(String url) {
    33. //...从私有云下载图片...
    34. }
    35. private void createBucketIfNotExisting(String bucketName) {
    36. // ...创建bucket...
    37. // ...失败会抛出异常..
    38. }
    39. }
    40. // ImageStore的使用举例
    41. public class ImageProcessingJob {
    42. private static final String BUCKET_NAME = "ai_images_bucket";
    43. //...省略其他无关代码...
    44. public void process() {
    45. Image image = ...;//处理图片,并封装为Image对象
    46. ImageStore imageStore = new PrivateImageStore(...);
    47. imagestore.upload(image, BUCKET_NAME);
    48. }
    49. }

    lesson 7:多用组合少用基础

    1.组合相比继承有哪些优势?

            可以利用组合、接口、委托三个技术手段,一块儿解决继承问题。

    1. public interface Flyable {
    2. void fly();
    3. }
    4. public interface Tweetable {
    5. void tweet();
    6. }
    7. public interface EggLayable {
    8. void layEgg();
    9. }
    10. public class Ostrich implements Tweetable, EggLayable {//鸵鸟
    11. //... 省略其他属性和方法...
    12. @Override
    13. public void tweet() { //... }
    14. @Override
    15. public void layEgg() { //... }
    16. }
    17. public class Sparrow impelents Flyable, Tweetable, EggLayable {//麻雀
    18. //... 省略其他属性和方法...
    19. @Override
    20. public void fly() { //... }
    21. @Override
    22. public void tweet() { //... }
    23. @Override
    24. public void layEgg() { //... }
    25. }

            接口只声明方法,不定义实现。也就是说,每个会下蛋的鸟都要实现下layEgg方法,并且实现逻辑都是一样的,这样就会导致代码重复问题,优化方案:针对三个接口,再定义三个实现类,然后通过组合/委托技术来消除代码重复。

    1. public interface Flyable {
    2. void fly();
    3. }
    4. public class FlyAbility implements Flyable {
    5. @Override
    6. public void fly() { //... }
    7. }
    8. //省略Tweetable/TweetAbility/EggLayable/EggLayAbility
    9. public class Ostrich implements Tweetable, EggLayable {//鸵鸟
    10. private TweetAbility tweetAbility = new TweetAbility(); //组合
    11. private EggLayAbility eggLayAbility = new EggLayAbility(); //组合
    12. //... 省略其他属性和方法...
    13. @Override
    14. public void tweet() {
    15. tweetAbility.tweet(); // 委托
    16. }
    17. @Override
    18. public void layEgg() {
    19. eggLayAbility.layEgg(); // 委托
    20. }
    21. }

    2.如何判断该用组合还是继承?

            如果类的结构稳定,继承层次比较浅(比如,最多有两层继承关系),继承关系不复杂,我们就可以大胆地使用继承。相反,系统越不文婷,继承层次越深,继承关系复杂,我们就尽量使用组合来代替继承。

            除此之外,一些设计模式会固定使用继承或者组合:比如,装饰着模式,策略模式,组合模式都是使用了组合关系,而模板模式使用了继承关系。

    lesson 8:案例实操

  • 相关阅读:
    北美”闲鱼”Poshmark,如何销售提高成单率?附防封养号攻略
    ffmpeg在fedora上的静态编译实战——筑梦之路
    MySQL 基础知识(一)之数据库和 SQL 概述
    MCU通过KT6368A用SPP透传发送1K左右的数据,手机APP显示是3个包或者4个包,但是我看手册说最大一个包是512,理论应该是两个包吧,请问这正常吗?
    spring-boot 请求参数校验:注解 @Validated 的使用、手动校验、自定义校验
    vue2 vue3 中指令总结
    浏览器原生JavaScript离线文字转语音TTS播放,支持Windows自带TTS语音和移动端(安卓、IOS)
    基于html+css+javascript+jquery+bootstarp响应式网页设计——大理我的家乡旅游景点
    实操Hadoop大数据高可用集群搭建(hadoop3.1.3+zookeeper3.5.7+hbase3.1.3+kafka2.12)
    vue - 大文件分片上传之simple-uploader.js的使用
  • 原文地址:https://blog.csdn.net/c243311364/article/details/126826005