草庐IT

读编程与类型系统笔记08_面向对象变成的元素

躺柒 2023-03-28 原文

1. 面向对象编程

1.1. (Object-Oriented Programming,OOP)

1.2. 基于对象的概念的一种编程范式

1.3. 对象可以包含数据和代码

1.4. 数据是对象的状态

1.5. 代码是一个或多个方法

1.5.1. 消息是方法,包括名称、实参和返回类型

1.6. 通过使用其他对象的方法,对象之间可以“对话”或者发送消息

1.7. 关键特征

1.7.1. 封装

1.7.1.1. 允许隐藏数据和方法

1.7.2. 继承

1.7.2.1. 用额外的数据和代码扩展一个类型

2. 接口

2.1. 契约

2.2. 描述了实现该接口的任何对象都理解的一组消息

2.3. 接口没有任何状态

2.4. 相当于书面协议

2.4.1. 规定了实现者将提供什么

2.5. ConsoleLogger满足了ILogger的契约

2.5.1. 并不是一个ILogger

2.5.2. Java和C#规定一个类只能从另外一个类继承,但它们允许类实现许多接口,这就是原因所在

2.6. 合并接口的能力允许我们从较小的、可重用的接口创建合并后的接口

2.7. 接口最终让消费者受益,而不是让实现接口的类获益

2.8. “针对接口编程”是著名的OOP原则

3. 抽象类

3.1. 可以包含非抽象的方法或状态

3.2. 和具体类的唯一区别在于不能直接创建抽象类的实例

3.3. ConsoleLogger和AbstractLogger之间的关系是所谓的“是”关系

3.3.1. ConsoleLogger继承了AbstractLogger

3.3.2. ConsoleLogger也是一个AbstractLogger

4. 继承

4.1. 子类是父类的子类型

4.1.1. 在期望使用父类的任何地方,都可以使用子类的实例

4.2. 继承会在子类型与父类型之间建立“是一个”关系

4.3. 不要创建出非常深的类层次

4.3.1. 一个对象的多个状态和方法可能来自层次结构中的不同级别,导致代码更难理解

4.4. 让子类是具体类,让层次结构上方的父类是抽象类,这是一个好主意

4.5. 尽可能多地使用final或sealed等关键字实现某个子类显式标记为不可继承

4.6. 使用继承来代表层次,或者通过使用抽象或重写方法来实现参数化行为

5. 组合

5.1. 比继承更好的方法

5.2. 只要可能,就优先选择组合而不是继承是著名的OOP原则

5.3. “有一个”经验准则

5.3.1. 不是从一个类型继承行为,而是定义一个该类型的属性

5.3.2. 对于判断什么时候应该使用组合而言是一个很好的测试

5.4. 除非两个类型之间存在清晰的“是一个”关系,否则组合是可以默认使用的好方法

5.5. 组合在容器类型和被包含类型之间建立了一种“有一个”关系

5.6. 优点:组件属性的所有状态被封装在这些组件中,所以类型变得整洁多了

5.7. 不是把几个组件合并到一起,而是封装一个组件,并提供它需要的“胶水”代码,使其能够作为另外一种类型使用

6. 值类型和 引用类型

6.1. 在C#中结构是值类型

6.2. 除了原生提供的基本数值类型,Java不支持值类型

6.2.1. 几乎所有类型都是引用类型

6.3. 在C++中

6.3.1. 所有类型都是按值传递的,除非我们显式地将一个值声明为指针(*)或者引用(&)

6.3.2. 结构只是意味着其成员默认是公有的

6.3.3. 类的成员默认是私有的

6.4. 一些函数式语言

6.4.1. 使用不可变数据

6.4.2. 此时不存在值和引用之间的区别

7. 适配器模式

7.1. 能够让两个类变得兼容,而且不需要我们修改其中任何一个类

7.2. 对于处理我们无法修改的代码极为有用

7.2.1. 例如不在我们控制内的外部库的代码

7.3. 不修改类型,而是使用封装和组合让类型适配不同接口的一个例子

8. 混入

8.1. 有争议的概念

8.2. 混入行为通常是使用多重继承实现的

8.2.1. 扩展阅读了解”菱形继承”问题

8.3. “是一个”经验准则发生了冲突

8.4. 在一个类型与其混入类型之间建立了“包含”关系

8.5. 许多语言为了保持简单,选择根本不支持混入

8.6. 大部分支持混入的语言中,混入另外一个类型与继承无法没有区别

8.7. 混入对于减少样板代码很有用

8.8. 混入最适合实现横切关注点(cross-cutting concern)

8.8.1. 引用计数

8.8.2. 缓存

8.8.3. 持久化

8.8.4. 日志

8.8.5. 安全

8.9. 编译时方案

8.9.1. 在C++中,我们可以使用多重继承来把一个类型声明为其他两个类型的组合

8.10. 运行时方案

8.10.1. 在TypeScript中的交叉类型

8.10.1.1. 使用extend()函数

8.11. 与继承不同,使用混入时,我们为不同的行为方面定义不同的类型,然后把它们合并起来,放到一个完整的类型中

8.11.1. 有一些属性和方法是特定对象所独有的

8.11.2. 另一些属性和方法是多个类型所共有的

8.12. 使用混合来为类型添加行为

9. 纯粹面向对象代码的替代方案

9.1. 它们不会替代OOP,但在一些情况中是更好的选择

9.2. 和类型

9.2.1. 以相同的方式传递不同类型的对象,或者把它们放到一个公共的集合中,使用和类型,此时不需要在类型之间建立任何关系,就可以获得相同的行为

9.3. 函数式编程

9.3.1. 避免了维护状态:函数可以接受一组实参,执行一些计算,然后返回结果,并不需要改变任何状态

9.3.2. 如果IExpression更加复杂,声明了多个方法,那么面向对象方法的效果可能更好

9.4. 泛型编程

有关读编程与类型系统笔记08_面向对象变成的元素的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  4. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  5. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  6. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  7. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  8. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  9. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  10. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

随机推荐