• 面向对象


    面向对象

    和面向过程的辨析#

    • 面向过程编程(Procedure Oriented Programming)

      核心思想:面向过程的核心是以过程或者说函数作为程序设计的基本单元,强调的是解决问题的步骤和顺序。

      特点

      • 程序结构清晰,通常体现为函数的组合和调用,关注的是如何一步步地执行操作。
      • 数据和处理数据的函数通常是分开的,通过函数参数传递数据。
      • 优点在于简洁明了,执行效率较高,适用于小型、逻辑相对简单的项目。
      • 缺点在于随着程序规模扩大,各部分之间的耦合度会增加,难以复用和维护,不便于管理复杂的系统。
    • 面向对象编程(Object Oriented Programming)

      核心思想:面向对象编程则是以“对象”为核心,将数据(属性)和操作数据的行为(方法)封装在一起,形成具有独立职责的对象。程序设计围绕着对象及其交互来进行

      特点:

      • 强调概念抽象,封装、继承和多态这三大特性。
      • 封装使得数据隐藏,对外提供接口,增强了安全性和减少耦合度。
      • 继承允许子类继承父类的属性和方法,减少代码重复并构建出层次化的类结构。
      • 多态使得同一接口可以有不同的表现形式,增加了代码的灵活性和扩展性。
      • 优点在于提高了代码的复用性、可维护性和可扩展性,更适应大型软件系统的开发。
      • 缺点包括学习成本相对较高,且过度设计可能导致性能损失(尤其是在大量创建对象时)

    总结来说,面向过程着重于算法和逻辑控制的流程,而面向对象则更关注现实世界的实体模型和其行为,强调的是利用对象间的交互来解决问题。在实际开发中,两者并不是绝对对立,现代编程实践中往往结合两者的优势,灵活运用在不同的场景中

    一个案例#

    需求:

    要设计一个简单的银行账户管理系统,需求如下:创建账户、存款、取款、查询余额

    面向过程编程#

    以方法,流程,全局变量来实现解决问题,实现目的

    import java.util.HashMap;
    import java.util.Map;
    
    public class BankProcess {
        // 全局账户字典用于存储账户信息
        static Map<String, Double> accounts = new HashMap<>();
    
        public static void main(String[] args) {
            createAccount("A001", 1000.0);
            deposit("A001", 500.0);
            System.out.println("Balance after deposit: " + checkBalance("A001"));
            withdraw("A001", 200.0);
            System.out.println("Balance after withdrawal: " + checkBalance("A001"));
        }
    
        // 创建账户
        public static void createAccount(String accountId, double initialBalance) {
            accounts.put(accountId, initialBalance);
        }
    
        // 存款操作
        public static void deposit(String accountId, double amount) {
            if (accounts.containsKey(accountId)) {
                accounts.put(accountId, accounts.get(accountId) + amount);
            }
        }
    
        // 取款操作
        public static void withdraw(String accountId, double amount) {
            if (accounts.containsKey(accountId) && accounts.get(accountId) >= amount) {
                accounts.put(accountId, accounts.get(accountId) - amount);
            }
        }
    
        // 查询余额
        public static double checkBalance(String accountId) {
            return accounts.getOrDefault(accountId, 0.0);
        }
    }
    

    面向对象编程#

    以对象,对象的属性,对象的行为(方法)来解决问题,实现目的

    import java.util.HashMap;
    import java.util.Map;
    
    class BankAccount {
        private String accountId;
        private double balance;
    
        public BankAccount(String accountId, double initialBalance) {
            this.accountId = accountId;
            this.balance = initialBalance;
        }
    
        public static BankAccount getAccount(String accountId) {
            return allAccounts.get(accountId);
        }
    
        public void deposit(double amount) {
            if (amount > 0) {
                balance += amount;
            }
        }
    
        public void withdraw(double amount) {
            if (amount > 0 && balance >= amount) {
                balance -= amount;
            }
        }
    
        public double checkBalance() {
            return balance;
        }
    
    }
    
    @Test
    public void test(){
        List<BankAccount> allAccounts = new ArrayList<>();
        BankAccount account = new BankAccount("A001", 1000.0);
        allAcounts.add()
        account.deposit(500.0);
        System.out.println("Balance after deposit: " + account.checkBalance());
        account.withdraw(200.0);
        System.out.println("Balance after withdrawal: " + account.checkBalance());
    }
    

    面向对象的三大特性#

    封装#

    将数据(属性)和操作数据的方法(函数或者方法)绑定在一起,作为一个整体(对象)进行考虑,通过封装,可以隐藏对象的内部细节,仅对外提供公共访问方式,从而提高代码的复用性和安全性。在程序设计中,对象的状态通常由其属性来体现,而行为则通过方法来执行

    继承#

    继承是一种创建新类的方式,新类可以从已有的类中派生出来,继承父类的属性和方法,同时也可以扩展新的属性和方法.这样可以提高代码的重用性,使得类和类之间产生了层次结构,便于系统的维护和扩展

    多态#

    多态,指为不同数据类型的实体提供统一的接口,以Java语言为例,多态有以下要素

    • 继承,多个子类继承/实现了一个父类
    • 重写,多个子类重写了父类的同名方法,有不同实现
    • 父类引用指向子类对象(默认调用子类的重写方法)
    //1.继承,父类
    public class Animal {
      public void shout();
    }
    
    //1.继承,一个子类
    @Slf4j
    public class Dog extends Animal {
        
      //2.重写了父类的方法  
      @Override
      public void shout() {
        log.info("wanwan");
      }
    }
    
    @Slf4j
    public class Cat extends Animal {
      @Override
      public void shout() {
        log.info("mimi");
      }
    }
    
    @Test
    public void test() {
        
      Animal ani = new Dog();//3.父类引用指向子类对象
      ani.shout();//3.调用子类dog重写后的方法 wanwan
        
    }
    

    上述代码展示了多态,支持多态就意味着,所有需要具体子类的地方都可以用父类笼统概括,最直观的莫过于,同一个方法用父类做形参,可以传入不同子类实现不同的功能,降低了耦合度,提高了扩展性

    面向对象的五大原则#

    单一职责原则(Single Responsibility Principle)#

    一个类或者模块应该有且只有一个改变的理由,即一个类应该只有一个职责,当且仅当它负责的功能发生变化时才需要修改

    开放封闭原则(Open/Close Principle)#

    类模块应该是可扩展的,但不可修改,在不修改已有代码的情况下,能够通过扩展模块的行为来添加新的功能

    为什么叫开放封闭原则?

    对扩展开放,对修改关闭

    里氏替换原则(Liskov Substitution Principle)#

    子类型必须能够替换掉它们的基类型。这意味着在继承体系中,子类应当可以在任何需要基类出现的地方无差别地替代基类,而且不会破坏原有的正确性

    为什么叫里氏替换原则?

    里斯科夫(Liskov)女士在 1987 年的“面向对象技术的高峰会议”(OOPSLA)上发表的一篇文章《数据抽象和层次》(Data Abstraction and Hierarchy)里提出来:"继承必须确保超类所拥有的性质在子类中仍然成立"

    接口隔离原则(Interface Segregation Principle)#

    接口隔离原则建立在使用接口的情况下,客户端不应该被迫使用对其无用的方法或者功能,一个类对另一个类的依赖应该建立在最小的接口上

    实践起来就是接口不应该过于臃肿和冗余,依赖一个臃肿冗余的接口,不如把这个接口拆成多个,来按需依赖

    依赖倒置原则(Dependence Inversion Principle)#

    • 高层模块(如业务逻辑层)不应该依赖于底层模块(如数据访问层),二者都应该依赖其抽象
    • 抽象不应该依赖细节,细节应该依赖抽象
    • 依赖倒置的核心是"面向接口编程"
    • 抽象对比细节,要稳定,以抽象为基础搭建的框架比细节的框架要稳定的多

    依赖倒置原则的依赖倒置体现在哪里?

    在传统的自底向上设计中,高层模块(如业务逻辑层)会直接依赖底层模块(如数据访问层)形成一种具体依赖具体的依赖关系

    个人理解的倒置,应该和高层,底层没什么关系,是一种理念上的倒置,即由依赖具体转变为依赖抽象

  • 相关阅读:
    超高清图像生成新SOTA!清华唐杰教授团队提出Inf-DiT:生成4096图像比UNet节省5倍内存。
    9月3日,每日信息差
    安洵杯2022 Web Writeup
    DQL语言进阶2
    rainbond 如何切换源码构建所需的builder镜像以及runner镜像拉取地址
    一段惊呆下巴的 JavaScript 代码
    Linux高级IO ----- select
    通过商品ID获取到京东商品详情页面数据,京东商品详情官方开放平台API接口,京东APP详情接口,可以拿到sku价格,销售价演示案例
    详解集群级备份恢复:物理细粒度备份恢复
    [源码+课后指导]_基于Java开发实现的订餐系统
  • 原文地址:https://www.cnblogs.com/void-cmy/p/18068363