J&C:集合概述 / 迭代器模式 / ER模型 / 仓储模式

更多
2021年08月31日 10点21分 作者:叶飞 修改

集合概览

集合是同一类型元素的组合,本身也是一个类/对象,就像一个容器一样,(可以)装着它的元素。

PS:早期的集合元素类型都是Object,但现在我们都使用泛型。(@想一想@:为什么?)

数组就是一种集合。

除此以外,Java和C#还内置了:

  • 存储单个元素的:Collecition,又分为:
    • 有序的、可以根据下标找到元素的:List(类似于数组,但比数组更强大)
    • 没有下标的、元素能不重复的Set

  • 存储键值对的:Map/Dictionary。
    成绩单就是典型的键值对,学生姓名就是,学生成绩就是
    一个班级所有学生成绩的成绩单就可以用Map/Dictionary存储,其特点是键不能重复,值可以重复,通过键就能找到值。

再下面又根据其数据结构,派生出:

  • Hash:哈希表
  • Queue:队列
  • Stack:栈
  • Tree:树
  • Linked:链表

以上粗体为Web开发常用集合。(理解起来觉得抽象的同学,可以先看Java/C#部分的演示)

所有集合中都内置了相应的增删改查等方法。

PS:现在终于可以回答这个问题:为什么实际开发中我没有写过数据结构和算法呢?


迭代器模式

所有的集合都有一个要求:遍历(迭代/枚举)每一个元素。

我们能不能提供一个统一的方法,实现这个功能?

很简单,让所有集合类实现一个接口(Java中Iterable/C#中IEnumerable),在接口中定义一个遍历的方法(Java中iterator()/C#中GetEnumerator()),不就OK了吗?

注意这个接口方法返回的值又是一个接口(Java中Iterator<T>/C#中IEnumerator<T>),它又有两个方法:

  • 迭代/枚举是否已经结束:Java中hasNext()/C#中MoveNext()
  • 给我当前/下一个元素:Java中next()/C#中Current)

这样,我们要遍历任何一个集合的时候,都只需要这样机械地调用:

//拿到集合students的迭代器
Iterator<Person> iterator = students.iterator();
//只要没有遍历结束
while(iterator.hasNext()) {	
	//获取下一个元素
	Person current = iterator.next();
	System.out.println(current.Name);
}

@想一想@:为什么还要引入Iterator,而不直接在Iterable中定义hasNext()和next()呢?

  • 封装:所有遍历的功能实现都交给Iterator去做(单一职责)
  • 重用:依赖于组合,而不是继承


学习前提:Java/C#中集合

ER模型

Entity-Relationship Model:实体关系模型。

什么是实体?

^_^,good question!

简单理解:实在在存在的物

面向对象的世界里,万物皆对象。但

有些对象是能够映射到现实世界实际存在的物体的,或者拥有实实在在的数据信息的,比如:

  • 学生Student,有姓名、年龄……
  • 课程Major,有名称、课时、难易程度……

他们就是实体。

有些对象则不然,他们没有对应的实体,在系统中作为辅助、运算、工具类存在,比如:生成随机数的Random对象,对应啥?对应一个色子?就算这样,这个色子本身也没有任何数据需要记录,我们只是需要它的运算结果。还有StringBuilder、集合对象……他们就不是实体。

PS:这个问题其实在学了数据库之后更好理解,凡是要存到数据库的,都是实体。

关系:引用/依赖

实体和实体之间,会产生关系。

可以通过一个对象的属性指向另一个/系列的对象来体现,这种组织形式又被称之为:引用/关联/组合(复习:继承是为了重用,重用使用组合

public class Student {
    private Teacher teacher;

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
}
Student atai = new Student();
Teacher fg = new Teacher();
atai.setTeacher(fg); 

PS:引用(属性依赖)是依赖关系的一种。依赖的概念比引用大,只要一个对象/类使用了另一个对象/类,就算是形成了依赖关系。

除了属性依赖,还可以有:

  • 构造函数依赖:构造函数的参数是另外一个对象
  • 方法依赖:方法的参数是另外一个对象
  • ……

X对X

我们也把对象之间的关联关系概括为(以老师/学生关系为例):

  • 一对一(1:1),1个老师只有1个学生  且 1个学生也只有1个老师 (现实世界:一夫一妻)
  • 一对多(1:n),1个老师有多个学生  且 1个学生只能有1个老师 (现实世界:一个妈妈多个孩子)
  • 多对多(n:n),1个老师有多个学生  且 1个学生可以有多个老师(现实世界:中小学老师学生)

注意:我们上面说的“有”,是规则允许“可以有”“最多有”的意思。比如:

  • 1:1,是一个丈夫可以有一个妻子,实际上他还没有,也OK的(没有1:0这种说法,或者说1:1其实就包含了1:0)
  • 1:n,实质上也可能是某个妈妈只有一个独生子女,但规则允许一个妈妈有多个孩子,那妈妈和孩子之间就是1:n的关系
  • n:n,我就省略了?^_^

表现形式

可以用单个属性引用表示1,集合表示n。比如一个学生多个老师:

关系首先可以分成单向双向,比如:

public class Student {
    private Teacher teacher;

public class Teacher {
    private Student student;

Student引用了Teacher,Teacher也引用了Student,我们就说Student和Teacher之间形成了“双向”引用。

代码演示

构建ER模型,可以灵活使用单向/双向关系:

  • 多对多:最简单,只能双向:
    public class Teacher {
    	private List<Student> students;
    public class Student {
        private List<Teacher> teachers;
    
  • 一对多:一个老师多个学生
    • 单向:
      • 1引用n:
        public class Student {
        	private Teacher teacher;
      • n引用1
        public class Teacher {
        	private List<Student> students;
    • 双向:上述两个单向代码都写上。
  • 一对一:通常使用双向,因为单向能确保是1:1
    public class Student {
    	private Teacher teacher;
    public class Teacher {
    	private Student student;

反向推导

然后,通过对象间引用,我们可以反推:


Student Teacher 可能的关系
双向 Teacher Student 1:1
Teacher IList<Student> 1:n
IList<Teacher> IList<Student> n:n
单向 Teacher 看内容:1:1或1:n
IList<Teacher> 1:n


Repoistory

用户注册,系统应该新生成了一个User对象(包含用户名密码等)

@想一想@:这个对象存放在哪里?假设我们把对象都存储在集合里,这个集合是静态的,还是实例的好?

用户登录,我们要在集合里去检查登录用户的输入是否正确

@想一想@:应该怎么操作?本质上是根据用户名进行检索查找。

某一天被用户注销,我们又该怎么办?当然是在集合中删除这个对象。

OK,现在总结出来,存放、查找删除都要封装成方法,这些方法放在哪里?

三种方案:

  1. User类的实例方法:存放和删除能够接受,但查找……
  2. User类的静态方法:马马虎虎,但是不如
  3. 新建一个专门的UserRepository类:最流行的模式,推荐,@想一想@:为什么?

对应enities,建立专门的repository(仓库类),有以下好处:

  • 职责分明:repository负责对象的存、取、删;entity负责对象的改。
  • repository作为独立的类,可以通过继承、泛型、组合等实现灵活的重用。
class Repository<T>{
	public static List<Object> entities;		//C#可以直接使用T
	
	public void Save(T entity) {
		entities.add(entity);
	}
	
	public void Delete() {
		entities.remove(this);
	}
}
class StudentRepository extends Repository<Student>{
	public boolean Find(String name) {


作业

  1. 让之前的双向链表,能够:被foreach迭代
  2. 在现有作业的基础上,观察一起帮文章板块,以此为蓝本,补充(如果还没有的话)声明:
    • 评论(Comment)类
    • 评价(Appraise)类:包括“赞(Agree)”和“踩(Disagree)”
    • 关键字(Keyword)类
    并构建以下关系:
    • 一篇文章可以有多个评论
    • 一个评论必须有一个它所评论的文章
    • 每个文章和评论都有一个评价
    • 一篇文章可以有多个关键字,一个关键字可以对应多篇文章
  3. 在之前“文章/评价/评论/用户/关键字”对象模型的基础上,添加相应的数据,然后新建相应的repository类,利用Linq(C#)或Stream(Java)完成以下操作:
    1. 找出“飞哥”发布的文章
    2. 找出2019年4月21日以后“小鱼”发布的文章
    3. 按发布时间升序/降序排列显示文章
    4. 统计每个用户各发布了多少篇文章
    5. 找出包含关键字“C#”或“.NET”的文章
    6. 找出评论数量最多的文章
    7. 找出每个作者评论数最多的文章

集合 迭代器 设计模式 仓储模式
赞: 0 踩: 0

打赏
已收到打赏的 帮帮币

你的 打赏 非常重要!
为了保证文章的质量,每一篇文章的发布,都已经消耗了作者 1 枚 帮帮币
没有“帮帮币”,作者无法发布新的文章。

全系列阅读
评论 / 0

后台开发


其他:WebForm和WebApi

其他ASP.NET框架,如WebForm、WebApi……

RazorPages(Core)

微软推荐的、最新的、基于Razor页面和.NET core的新一代Web项目开发技术,包括Razor Tag Helper、Model绑定和Validation、Session/Cookie、内置依赖注入等……

MVC(Framework)

过去两年间最流行的、基于.NET Framework和MVC模式的ASP.NET MVC框架,主要用于讲解安全、性能、架构和各种实战功能演示……

C#语法

从入门的变量赋值、分支循环、到面向对象,以及更先进的语言特性,如:泛型、Lambda、Linq、异步方法等…………

Java语法

面向过程的变量赋值、分支循环和函数封装;面向对象的封装、继承和多态;以及更高阶的常用类库(集合/IO/多线程……)、lambda等

Java Web开发

SpringMVC

分层架构和综合实战

J&C

Java和C#共有的语法

全部
关键字



帮助

反馈