面向对象软件编程——OOP入门实践

2024-09-02 08:44

本文主要是介绍面向对象软件编程——OOP入门实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

工作一段时间了,工作内容趋向于算法模型的复现,就是复现论文算法然后结合业务逻辑开发软件。但是在设计和开发软件时,发现对于OOP理念和软件的设计原则等在实战中还是非常缺乏。于是开始补习,基础软件开发技术。

书籍:《深入浅出WPF》

作者:刘铁猛

序:WPF(Windows Presentation Foundation)编写程序表示层的技术与工具。

程序架构: 表示层(View)<-->业务逻辑层(ViewModel)<-->数据层(Model)。也就是一般常说的MVVM

数据模型:现实世界中事物和逻辑的抽象。

业务逻辑:数据模型之间的关系与交互。

用户界面:由控件构成的、与用户进行交互的界面,用于把数据展示给用户并响应用户的输入。

好,序结束了,本书可以暂告一段落了。先插入OOP,再来WPF的具体开发。

OOP(Object-Oriented Programming)实践:(以下代码示例由ChatGPT给出)

目录

1. 对象组合

1.1 一对一对象组合:两种典型的对象组合方式

1.1.1 方式一: 完全包容

1.1.2 方式二:独立方式

1.2 一对多

​编辑

1.2.1 方式一:完全包含

1.2.2 方式二:独立方式

1.3 延时动态对象组合

1.4 对象组合的特殊形式——自引用类

示例:链表中的自引用

自引用类的应用场景:

自引用类的特点:


1. 对象组合

假设我们有一个 Engine 类和一个 Wheels 类,通过组合它们,我们可以创建一个 Car 类,而不必通过继承的方式来实现。

class Engine:def start(self):print("Engine started")class Wheels:def roll(self):print("Wheels rolling")class Car:def __init__(self, engine, wheels):self.engine = engineself.wheels = wheelsdef drive(self):self.engine.start()self.wheels.roll()# 使用对象组合
engine = Engine()
wheels = Wheels()
car = Car(engine, wheels)
car.drive()

1.1 一对一对象组合:两种典型的对象组合方式

1.1.1 方式一: 完全包容

在面向对象编程中,如果对象 A 完全包容对象 B,并且容器对象 A 管理被包容对象 B 的生命周期,这种关系通常被称为 组合(Composition)

下面是一个使用 C# 语言的例子,

  • Engine 类 定义了引擎的启动和停止行为。

  • Car 类 内部包含一个 Engine 对象,并在 Car 对象的构造函数中创建该对象。

  • Car 类 通过 DriveStop 方法来操作其内部的 Engine 对象。

  • Car 对象被销毁时,Engine 对象也随之被销毁。这种关系说明 Car 对象完全控制了 Engine 对象的生命周期。

在这个例子中,Car 对象是容器对象,它负责创建和销毁 Engine 对象,展示了组合关系中的生命周期管理。

using System;class Engine
{public void Start(){Console.WriteLine("Engine started");}public void Stop(){Console.WriteLine("Engine stopped");}
}class Car
{private Engine _engine;public Car(){_engine = new Engine();  // Car对象创建时,同时创建Engine对象}public void Drive(){_engine.Start();Console.WriteLine("Car is driving...");}public void Stop(){_engine.Stop();Console.WriteLine("Car has stopped.");}~Car(){// 在Car对象销毁时,同时销毁Engine对象Console.WriteLine("Car is being destroyed, so is the engine.");_engine = null;}
}class Program
{static void Main(){Car car = new Car();car.Drive();car.Stop();// Car对象出作用域时,垃圾回收器将最终销毁Car对象和它包含的Engine对象}
}

1.1.2 方式二:独立方式

在面向对象编程中,如果对象 B 是独立的,并且对象 A 只是引用一个现成的 B 对象,而不负责管理 B 对象的生命周期,这种关系通常被称为 聚合(Aggregation)。在聚合关系中,被引用的对象可以被多个其他对象共享,它的生命周期独立于引用它的对象。

  • Engine 类 定义了引擎的启动和停止行为,与前面的例子相同。

  • Car 类 在其构造函数中接受一个 Engine 对象的引用,但并不创建或销毁该对象。

  • Main 方法中,sharedEngine 是一个独立的 Engine 对象,它的生命周期独立于任何 Car 对象。

  • Car1 和 Car2 都引用同一个 sharedEngine 对象,这表明它们之间存在聚合关系。

在这个例子中,Car 对象和 Engine 对象之间的关系是聚合关系,因为 Car 对象只引用现成的 Engine 对象,而不管理它的生命周期。

using System;class Engine
{public void Start(){Console.WriteLine("Engine started");}public void Stop(){Console.WriteLine("Engine stopped");}
}class Car
{private Engine _engine;// 构造函数接受一个现成的 Engine 对象public Car(Engine engine){_engine = engine;}public void Drive(){_engine.Start();Console.WriteLine("Car is driving...");}public void Stop(){_engine.Stop();Console.WriteLine("Car has stopped.");}
}class Program
{static void Main(){Engine sharedEngine = new Engine();  // 创建一个独立的 Engine 对象Car car1 = new Car(sharedEngine);  // 引用现成的 Engine 对象Car car2 = new Car(sharedEngine);  // 另一个 Car 对象也引用同一个 Engine 对象car1.Drive();car1.Stop();car2.Drive();car2.Stop();// sharedEngine 对象的生命周期独立于 car1 和 car2}
}

1.2 一对多

1.2.1 方式一:完全包含

一对多完全包容的特点:

  • 生命周期管理:容器对象(如 Team)负责管理所有子对象(如 Player)的生命周期。一旦容器对象销毁,所有子对象也会被销毁。

  • 封装性:所有子对象都被容器对象内部管理,外部不需要直接处理这些子对象。

  • 统一管理:通过使用集合类型(如 List<Player>),可以方便地对多个子对象进行统一管理和操作。

一对多组合关系的例子,其中一个 Team 对象完全包容并管理多个 Player 对象:

using System;
using System.Collections.Generic;class Player
{public string Name { get; }public Player(string name){Name = name;}public void Play(){Console.WriteLine($"{Name} is playing.");}
}class Team
{private List<Player> _players;public Team(){_players = new List<Player>();  // 初始化列表以管理多个Player对象}public void AddPlayer(string playerName){Player player = new Player(playerName);  // 创建并添加新Player对象_players.Add(player);}public void PlayGame(){Console.WriteLine("The team is playing the game:");foreach (var player in _players){player.Play();}}~Team(){// 在Team对象销毁时,Player对象会随之销毁Console.WriteLine("Team is being destroyed, so are the players.");_players.Clear();}
}class Program
{static void Main(){Team team = new Team();team.AddPlayer("Alice");team.AddPlayer("Bob");team.AddPlayer("Charlie");team.PlayGame();// 当 team 对象出作用域并被垃圾回收时,Player 对象也会被销毁}
}

1.2.2 方式二:独立方式

一对多独立关系的特点:

  • 独立的生命周期Student 对象的生命周期独立于 School 对象,即使 School 对象被销毁,Student 对象依然可以存在并被其他对象引用。

  • 共享性:多个 School 对象可以共享同一个 Student 对象,或者 Student 对象可以被其他地方使用,而不仅仅是被某个特定的 School 对象引用。

  • 低耦合性School 对象和 Student 对象之间的关系是低耦合的,School 仅仅是引用和使用 Student,而不负责其生命周期管理。

一对多聚合关系的例子,其中一个 School 对象引用多个独立的 Student 对象:

using System;
using System.Collections.Generic;class Student
{public string Name { get; }public Student(string name){Name = name;}public void Study(){Console.WriteLine($"{Name} is studying.");}
}class School
{private List<Student> _students;public School(){_students = new List<Student>();  // 初始化列表用于引用多个Student对象}public void AddStudent(Student student){_students.Add(student);  // 将独立的Student对象添加到School中}public void StartClasses(){Console.WriteLine("School is starting classes:");foreach (var student in _students){student.Study();}}
}class Program
{static void Main(){// 创建独立的Student对象Student student1 = new Student("Alice");Student student2 = new Student("Bob");Student student3 = new Student("Charlie");// 创建School对象School school = new School();// 将Student对象添加到School中school.AddStudent(student1);school.AddStudent(student2);school.AddStudent(student3);// 开始上课,所有学生都参与学习school.StartClasses();// Student对象的生命周期独立于School对象// 即使School对象销毁,Student对象仍然存在并可以被其他对象引用}
}

1.3 延时动态对象组合

延时动态对象组合是一种设计模式,其中对象的组合并不是在对象创建时立即完成,而是在需要时动态地完成。这种模式通常用于延迟初始化,资源管理,或者当组合的对象在创建时不一定存在时。通过延时组合,可以提高系统的灵活性和性能,特别是在对象的创建和初始化成本较高的情况下。

延时动态对象组合的优势:

  • 性能优化:对象只在需要时才会被创建,节省了系统资源,特别是当对象创建代价高或对象不一定总是需要时。

  • 提高灵活性:延迟初始化允许系统在不同的时间点根据需要动态组合对象,从而可以灵活地响应运行时的需求。

  • 资源管理:避免在程序启动时创建不必要的对象,减少内存占用和初始化时间。

一个 Document 对象,其中包含一个 Printer 对象。Printer 对象只有在需要时才会被创建和初始化:

using System;class Printer
{public Printer(){Console.WriteLine("Printer is initialized.");}public void Print(string content){Console.WriteLine($"Printing: {content}");}
}class Document
{private Printer _printer;// 延时初始化 Printer 对象public Printer Printer{get{if (_printer == null){_printer = new Printer();  // 在需要时才初始化 Printer 对象}return _printer;}}public void PrintDocument(string content){Console.WriteLine("Preparing to print document...");Printer.Print(content);  // 使用延时初始化的 Printer 对象进行打印}
}class Program
{static void Main(){Document doc = new Document();// Document 对象创建时,Printer 对象尚未初始化Console.WriteLine("Document created.");// 只有在需要打印时,Printer 对象才会被初始化doc.PrintDocument("Hello, World!");// 如果不需要打印,Printer 对象将不会被创建}
}
Document created.
Preparing to print document...
Printer is initialized.
Printing: Hello, World!

解释:

  • Printer 类:定义了一个 Printer 对象,它有一个 Print 方法用于打印内容。在创建 Printer 对象时会输出初始化信息。

  • Document 类

    • 包含一个私有的 Printer 字段 _printer,初始值为 null

    • 通过一个 Printer 属性进行延时初始化。只有在第一次访问 Printer 属性时,_printer 才会被创建和初始化。

    • PrintDocument 方法中使用了 Printer 属性。当需要打印文档时,Printer 对象才会被动态创建和使用。

  • Main 方法

    • 创建了一个 Document 对象时,并没有立即创建 Printer 对象。

    • 只有在调用 PrintDocument 方法时,Printer 对象才会被初始化和使用。

    • 上述两种非延时动态对象组合的方式,在Main中将所有独立的对象都进行了初始化,或者通过对象A的初始化是,对象B也在对象A的类内部进行了初始化。

1.4 对象组合的特殊形式——自引用类

自引用类是一种特殊形式的对象组合,其中一个类包含一个对同类对象的引用。自引用类常用于构建递归结构或树形结构,如链表、树、图等数据结构。通过自引用,一个对象可以引用另一个同类型的对象,形成层次化或递归的结构。

示例:链表中的自引用

链表是一个常见的自引用结构。每个节点(Node)都包含一个数据部分以及一个指向下一个节点的引用。这种结构允许创建一个动态大小的序列。

使用 C# 实现的单向链表,其中 Node 类是一个自引用类:

using System;class Node
{public int Data { get; set; }public Node Next { get; set; }  // 自引用,指向同类型的下一个节点public Node(int data){Data = data;Next = null;}
}class LinkedList
{private Node head;public LinkedList(){head = null;}// 添加节点到链表末尾public void Add(int data){Node newNode = new Node(data);if (head == null){head = newNode;  // 链表为空时,设置新节点为头节点}else{Node current = head;while (current.Next != null){current = current.Next;  // 找到链表的最后一个节点}current.Next = newNode;  // 将新节点连接到链表末尾}}// 打印链表中的所有节点public void PrintAllNodes(){Node current = head;while (current != null){Console.WriteLine(current.Data);current = current.Next;}}
}class Program
{static void Main(){LinkedList list = new LinkedList();list.Add(1);list.Add(2);list.Add(3);list.PrintAllNodes();  // 输出链表中的所有节点值}
}

自引用类的应用场景:

  • 链表:如示例中的单向链表、双向链表、循环链表等。

  • 树结构:如二叉树、B 树、红黑树等,每个节点包含对子节点的引用。

  • 图结构:节点间包含相互引用,形成复杂的网络关系。

  • 递归结构:支持递归定义和操作的复杂数据结构。

自引用类的特点:

  • 递归结构:自引用类可以自然地表达递归结构,适用于分层或递归数据的表示和操作。

  • 动态结构:通过自引用,可以构建动态大小和深度的数据结构,如链表和树。

  • 灵活性:自引用允许对象在运行时动态地链接和操作其他同类对象,提供灵活的数据管理能力。

自引用类的设计模式在构建动态、递归或分层结构时非常有用,广泛应用于各种数据结构和算法中。

这篇关于面向对象软件编程——OOP入门实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129510

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al