命名空间
知识点一 命名空间基本概念
概念
命名空间是用来组织和重用代码的
作用
就像是一个工具包,类就像是一件一件的工具,都是申明在命名空间中的
知识点二 命名空间的使用
基本语法
namespace 命名空间名
{类类
}
namespace MyGame
{class GameObject{}
}namespace MyGame
{class Player:GameObject{}
}
知识点四 不同命名空间中允许有同名类
namespace MyGame2
{在不同的命名空间中 是可以有同名类的class GameObject{}
}
知识点五 命名空间可以包裹命名空间
namespace MyGame {namespace UI{class Image{}}namespace Game{class Image{}} }
知识点六 关于修饰类的访问修饰符
public —— 命名空间中的类 默认为public
internal —— 只能在该程序集中使用
abstract —— 抽象类
sealed —— 密封类
partial —— 分部类
知识点三 不同命名空间中相互使用 需要引用命名空间或指明出处
GameObject g = new GameObject();
Image img0 = new Image();
MyGame.UI.Image img = new MyGame.UI.Image();
MyGame.Game.Image img2 = new MyGame.Game.Image();
总结
1.命名空间是个工具包 用来管理类的
2.不同命名空间中 可以有同名类
3.不同命名空间中相互使用 需要using引用命名空间 或者 指明出处
4.命名空间可以包裹命名空间
万物之父中的方法
知识回顾
万物之父 object
所有类型的基类 是一个引用类型
可以利用里氏替换原则装载一切对象
存在装箱拆箱
using System;namespace Lesson22_面向对象相关_万物之父中的方法 {class Test{public int i = 1;public Test2 t2 = new Test2();public Test Clone(){return MemberwiseClone() as Test;}public override bool Equals(object obj){return base.Equals(obj);}public override int GetHashCode(){return base.GetHashCode();}public override string ToString(){return "怪盗基德申明的Test类";}}class Test2{public int i = 2;}class Program{static void Main(string[] args){Console.WriteLine("万物之父中的方法");Console.WriteLine(t);#endregion}}
知识点一 object中的静态方法
静态方法 Equals 判断两个对象是否相等
最终的判断权,交给左侧对象的Equals方法,
不管值类型引用类型都会按照左侧对象Equals方法的规则来进行比较
Console.WriteLine(Object.Equals(1, 1));Test t = new Test();Test t2 = new Test();Console.WriteLine(Object.Equals(t, t2));
静态方法ReferenceEquals
比较两个对象是否是相同的引用,主要是用来比较引用类型的对象。
值类型对象返回值始终是false。
Console.WriteLine(Object.ReferenceEquals(t, t2));
知识点二 object中的成员方法
普通方法GetType
该方法在反射相关知识点中是非常重要的方法,之后我们会具体的讲解这里返回的Type类型。
该方法的主要作用就是获取对象运行时的类型Type,
通过Type结合反射相关知识点可以做很多关于对象的操作。
Test t = new Test();Type type = t.GetType();
普通方法MemberwiseClone
该方法用于获取对象的浅拷贝对象,口语化的意思就是会返回一个新的对象,
但是新对象中的引用变量会和老对象中一致。Test t2 = t.Clone();Console.WriteLine("克隆对象后");Console.WriteLine("t.i = " + t.i);Console.WriteLine("t.t2.i = " + t.t2.i);Console.WriteLine("t2.i = " + t2.i);Console.WriteLine("t2.t2.i = " + t2.t2.i);t2.i = 20;t2.t2.i = 21;Console.WriteLine("改变克隆体信息后");Console.WriteLine("t.i = " + t.i);Console.WriteLine("t.t2.i = " + t.t2.i);Console.WriteLine("t2.i = " + t2.i);Console.WriteLine("t2.t2.i = " + t2.t2.i);
知识点三 object中的虚方法
虚方法Equals
默认实现还是比较两者是否为同一个引用,即相当于ReferenceEquals。
但是微软在所有值类型的基类System.ValueType中重写了该方法,用来比较值相等。
我们也可以重写该方法,定义自己的比较相等的规则虚方法GetHashCode
该方法是获取对象的哈希码
(一种通过算法算出的,表示对象的唯一编码,不同对象哈希码有可能一样,具体值根据哈希算法决定),
我们可以通过重写该函数来自己定义对象的哈希码算法,正常情况下,我们使用的极少,基本不用。虚方法ToString
该方法用于返回当前对象代表的字符串,我们可以重写它定义我们自己的对象转字符串规则,
该方法非常常用。当我们调用打印方法时,默认使用的就是对象的ToString方法后打印出来的内容。
总结
1.虚方法 toString 自定字符串转换规则
2.成员方法 GetType 反射相关
3.成员方法 MemberwiseClone 浅拷贝
4.虚方法 Equals 自定义判断相等的规则
结构体和类的区别
区别概述
结构体和类最大的区别是在存储空间上的,因为结构体是值,类是引用,
因此他们的存储位置一个在栈上,一个在堆上,通过之前知识点的学习,我相信你能够从此 处看出他们在使用的区别——值和引用对象在赋值时的区别。结构体和类在使用上很类似,结构体甚至可以用面向对象的思想来形容一类对象。
结构体具备着面向对象思想中封装的特性,但是它不具备继承和多态的特性,因此大大减少了它的使用频率。
由于结构体不具备继承的特性,所以它不能够使用protected保护访问修饰符。
细节区别
1.结构体是值类型,类是引用类型
2.结构体存在栈中,类存在堆中
3.结构体成员不能使用protected访问修饰符,而类可以
4.结构体成员变量申明不能指定初始值,而类可以
5.结构体不能申明无参的构造函数,而类可以
6.结构体申明有参构造函数后,无参构造不会被顶掉
7.结构体不能申明析构函数,而类可以
8.结构体不能被继承,而类可以
9.结构体需要在构造函数中初始化所有成员变量,而类随意
10.结构体不能被静态static修饰(不存在静态结构体),而类可以
11.结构体不能在自己内部申明和自已一样的结构体变量,而类可以
结构体的特别之处
结构体可以继承 接口 因为接口是行为的抽象
如何选择结构体和类
1.想要用继承和多态时,直接淘汰结构体,比如玩家、怪物等等
2.对象是数据集合时,优先考虑结构体,比如位置、坐标等等
3.从值类型和引用类型赋值时的区别上去考虑,比如经常被赋值传递的对象,并且改变赋值对象,原对象不想跟着变化时,就用结构体。比如坐标、向量、旋转等等.
抽象类和接口的区别
知识回顾
抽象类和抽象方法
abstract修饰的类和方法
抽象类 不能实例化
抽象方法只能在抽象类中申明 是个纯虚方法 必须在子类中实现接口
interface 自定义类型
是行为的抽象
不包含成员变量
仅包含方法、属性、索引器、事件,成员都不能实现,建议不写访问修饰符,默认public
知识点一 相同点
1.都可以被继承
2.都不能直接实例化
3.都可以包含方法申明
4.子类必须实现未实现的方法
5.都遵循里氏替换原则
知识点二 区别
1.抽象类中可以有构造函数;接口中不能
2.抽象类只能被单一继承;接口可以被继承多个
3.抽象类中可以有成员变量;接口中不能
4.抽象类中可以申明成员方法,虚方法,抽象方法,静态方法;接口中只能申明没有实现的抽象方法
5.抽象类方法可以使用访问修饰符;接口中建议不写,默认public
如何选择抽象类和接口
表示对象的用抽象类,表示行为拓展的用接口
不同对象拥有的共同行为,我们往往可以使用接口来实现
举个例子:
动物是一类对象,我们自然会选择抽象类;而飞翔是一个行为,我们自然会选择接口。
UML类图
UML
简单理解:
使用一些高级的UML可视化软件,不用写代码,通过做一
些图表相关内容就可以直接生成代码,在其基础上进行开发。
它的最终目标是直接能通过图形就把业务逻辑就完成了。
UML类图
UML类图是UML其中很小的一部分
我们学习它的目的是帮助我们进行面向对象程序开发时
理清对象关系,养成面向对象编程习惯
VISIO
UML类图中的关系说明
关联:比如类A会有一个类B成员作为它的成员变量
直接关联:比如母鸡类中有一个行为是下蛋,它和气候直接关联
聚合:比如地图类聚合围墙类,鸟群类聚合大雁类(有点包含的感觉)
依赖关系:比如动物类依赖于空气类和水类
复合:比如公司类包含各种部门类,部门类和公司类的关系就是复合关系
总结
UML类图的主要作用是
帮助我们前期或者后期建立面向对象编程中的各种类
帮助我们理清类、接口相互之间的关系
至少在做项目前,我就知道我要建立几个类,几个接口了
让我们的编程思路更清晰
总结
强调
面向对象是程序开发中
极其重要的内容
把每个知识点弄懂了
可以让你少走弯路
面向对象七大原则
为什么有七大原则
七大原则总体要实现的目标是:
高内聚、低耦合
使程序模块的可重用性、移植性增强
高内聚低耦合
从类角度来看,高内聚低耦合:
减少类内部,对其他类的调用
从功能块来看高内聚低耦合:
减少模块之间的交互复杂度
七大原则
单一职责原则
接口隔离原则
开闭原则
合成复用原则
里氏替换原则
依赖倒转原则
迪米特法则
单一职责原则
SRP(Single Responsibility Principle)
类被修改的几率很大,因此应该专注于单一的功能。
如果把多个功能放在同一个类中,功能之间就形成了关联,改变
其中一个功能,有可能中止另一个功能。
举例:假设程序、策划、美术三个工种是三个类,他们应该各司
其职,在程序世界中只应该做自已应该做的事情。
开闭原则
OCP(Open-Closed Principle)
对拓展开发,对修改关闭
拓展开放:模块的行为可以被拓展从而满足新的需求
修改关闭:不允许修改模块的源代码(或者尽量使修改最小化)
举例:继承就是最典型的开闭原则的体现,可以通过添加新的子
类和重写父类的方法来实现
里氏替换原则
LSP(Liskov Substitution Principle)
任何父类出现的地方,子类都可以替代
举例:用父类容器装载子类对象,因为子类对象包含了父类的所
有内容
依赖倒转原则
DIP(Dependence Inversion Principle)
要依赖于抽象,不要依赖于具体的实现
迪米特原则
LoP(Law of Demeter)
又称最少知识原则
一个对象应当对其它对象尽可能少的了解
不要和陌生人说话
举例:一个对象中的成员,要尽可能少的直接和其它类建立关系
目的是降低耦合性
接口分离原则
ISP(Interface Segregation Principle)
不应该强迫别人依赖他们不需要使用的方法
一个接口不需要提供太多的行为,一个接口应该尽量只提供一个对外
的功能,让别人去选择需要实现什么样的行为,而不是把所有的行为
都封装到一个接口当中
举例:飞行接口、走路接口、跑步接口等等虽然都是移动的行为
但是我们应该把他们分为一个一个单独的接口,让别人去选择使用
合成复用原则
CRP(Composite Reuse Principle)
继承关系是强耦合,组合关系是低耦合
举例:脸应该是眼镜、鼻子、嘴巴、耳朵的组合,而不是依次的继承
角色和装备也应该是组合,而不是继承
注意:不能盲目的使用合成复用原则,要在遵循迪米特原则的前提下
七大原则
单一职责原则:一个类只处理自己应该处理的内容,不应该啥都写在一起
开闭原则:对拓展开放,对修改封闭。新加功能尽量是加处理而不是改代码
里氏替换原则:任何地方子类都能替代父类,父类容器装子类
依赖倒转原则:不要依赖具体的实现,要依赖抽象(接口)
迪米特法则:一个类要尽量减少对别的类的了解,尽量少用别的类和自己关联
接口隔离原则:一个接口一个行为,不要一个接口n个行为
合成复用原则:除非设计上需要继承,否则尽量用组合复用的形式
如何使用这些原则
在开始做项目之前,整理UML类图时
先按自已的想法把需要的类整理出来
再把七大原则截图放在旁边,基于七大原则去
优化整理自已的设计
整体目标就是:高内聚,低耦合
提醒
初学程序阶段
不要过多的纠结于七大原则
先用最适合自己的方法把需求实现了
再使用七大原则去优化
不要想着一步到位,要循序渐进
面向对象编程能力提升是需要经验积累的