面向对象

面向接口、面向对象、面向方面编程的区别

面向接口:本身就是面向对象的,无所谓区别,只不过面向接口的好处是耦合性低;它的原则是先定义好行为规范,再根据行为规范创建实现,严格的来说,面向接口应该是面向对象中的一部分吧,因为面向对象也强调的是依赖倒置原则,也就是实现依赖于抽象,而抽象不依赖于具体实现,更具比较的应该是面向接口与面向抽象对象,我的体会是面向接口更加灵活,但实现时候,稍微有些代码冗余

面向对象:一切元素都是对象,在设计时以对象为单位,考虑它的属性及方法。设计中采用了封装、继承、抽象的手法;而面向抽象可以结合面向接口,先定义接口,再定义抽象类,在抽象类中处理一些公共逻辑,再实现具体实现类。面向对象是对复杂问题的分解。面向对象的特征:封装、继承、多态以及抽象
类定义了对象的相关数据和方法,类通过构造函数生成对象,对象实现类的定义,且拥有具体的数据。
面向方面:Aspect-Oriented Programming (AOP) 就是大名鼎鼎的AOP。通过预编译方式和运行期动态代理实现程序功能的中统一处理业务逻辑的一种技术,比较常见的场景是:日志记录,错误捕获、性能监控等,MVC里面的filter等
它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术
它的优势主要表现在:
1、将通用功能从业务逻辑中抽离出来,可以省略大量重复代码,有利于代码的操作和维护。
2、在软件设计时,抽出通用功能(切面),有利于软件设计的模块化,降低软件架构的复杂度。也就是说通用的功能都是一个单独的模块,在项目的主业务里面是看不到这些通用功能的设计代码的。
其实MVC已经为我们提供了两种实现AOP的方式:
1.中间件(Middleware),这是MVC中的大杀器,提供了日志、Cookie、授权等一系列内置的中间件,从中可以看出,MVC并不想我们通过DP实现AOP,而是要在管道中做文章。
2. 过滤器(Filter),Filter是 ASP.NET MVC的产物,曾经一度帮助我们解决了异常、授权等逻辑,在Core时代我们仍然可以采用这种方式。

AOP相关概念,简单谈谈MEF在我们项目里面的使用吧。
在谈MEF之前,我们必须要先谈谈DIP、IOC、DI
依赖倒置原则(DIP):一种软件架构设计的原则(抽象概念)
控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。
依赖注入(DI):IoC的一种实现方式,用来反转依赖(IoC的具体实现方式)。
什么意思呢?也就是说,我们在软件架构的过程中,层和层之间通过接口依赖,下层不是 直接给上层提供实现,而是提供接口,具体的实现以依赖注入的方式在运行的时候动态注入进去。MEF就是实现依赖注入的一种组件。它的使用使得UI层不直接 依赖于BLL层,而是依赖于中间的一个IBLL层,在程序运行的时候,通过MEF动态将BLL里面的实现注入到UI层里面去,这样做的好处是减少了层与层 之间的耦合。这也正是面向接口编程方式的体现。

面向对象的思想主要包括什么

继承:子类拥有父类的所有数据和操作;
封装:用抽象的数据类型将数据和基于数据的操作封装在一起,数据被保护在抽象数据类型内;
多态:一个程序中同名的不同方法共存的情况。有两种形式的多态——重载与重写;
继承
在c#中,当一个类型被构造时,它的构造顺序是这样的:
先执行成员变量的初始化表达式,然后执行父类的构造(需要的话),最后调用自己的构造方法

结构和类的区别

结构是值类型,类是引用类型。
结构不支持继承,但可以实现接口。
结构不能定义无参数的构造函数,但可以声明有参的构造函数。也不能为成员变量定义初始值,必须通过构造函数来赋值,但静态成员可以直接赋初值。
结构作为一个微型的值类型的“类”,常用于存储数据的集合,而那些涉及到复杂操作的类型,应该被设计成类而不是结构。而类表现为行为
无抽象结构,但有抽象类(abstract);
class可以声明protected成员、virtual成员、sealed成员和override成员;而struct不可以,但是值得注意的是,struct可以重载System.Object的3个虚方法,Equals()、ToString()和GetHashTable();

接口和类有什么异同

相同点:
1、接口、类和结构都可以从多个接口继承;
2、接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员;
3、接口和类都可以包含事件、索引器、方法和属性;
不同点:
1、不能直接实例化接口;
2、接口只包含方法或属性的声明,不包含方法的实现;
3、接口可以多继承,类只能单继承
4、类有分部类的概念,定义可在不同的源文件之间进行拆分;
5、表达的含义不同,接口主要定义一种规范,统一调用方法,也就是规范类,约束类,类是方法功能的实现和集合;

您在什么情况下会用到虚方法或抽象类、接口

如果某个方法可能在派生类中会被重写。这时就将该方法写为虚方法;

抽象类:是一个类型,与派生类之间的关系是一个“is-a”的关系。用来做基类,抽象类不能创建对象,类中包括抽象方法和实例方法;

接口:是设计一个规范,描述了 Can do ;与实现类之间是种“like-a”的关系,C#中接口不能包含字段访问修饰符;

虚方法与抽象方法

virtual 关键字用于在基类中修饰方法。virtual的使用会有两种情况:

情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。
情况2:在基类中定义了virtual方法,然后在派生类中使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法
虚方法的作用是为了实现运行时多态,增强应用程序的灵活性,多态。

abstract关键字只能用在抽象类中修饰方法,并且没有具体的实现。抽象方法的实现必须在派生类中使用override关键字来实现。请务必将抽象方法放在抽象类中。派生类必须全部实现父类的方法。
抽象方法必须出现在抽象类中,且必须被重写。虚方法不需要,可以重写也可以不重写。

sealed

  • 定义
    sealed修饰符表示密封用于类时,表示该类不能再被继承,不能和 abstract 同时使用,因为这两个修饰符在含义上互相排斥。用于方法和属性时,表示该方法或属性不能再被重写,必须和 override 关键字一起使用,sealed是对虚方法或虚属性,也就是同override一起使用 sealed override
  • 密封类与抽象类
    密封类不能同时又是抽象类,因为密封类不能用作基类、也不能被继承,而抽象类总是希望被继承的。
  • 什么情况下使用密封类
    需要阻止其它程序员无意中继承该类的时候;在程序运行时需要起到优化效果的时候,可以使用密封类。

new

1)new 运算符:用于创建对象和调用构造函数。这种大家都比较熟悉,没什么好说的了。
2)new 修饰符:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。
3)new 约束:用于在泛型声明中约束可能用作类型参数的参数的类型。new约束指定泛型类声明中的任何类型参数都必须具有公共的无参数构造函数。
class ItemFactory where T : new()

static

  • 静态类
    [1] 仅包含静态成员。
    [2] 无法实例化。
    [3] 静态类的本质,是一个抽象的密封类,所以不能被继承,也不能被实例化
    [4] 不能包含实例构造函数
    [5] 如果一个类下面的所有成员,都需要被共享,那么可以把这个类定义为静态类。
  • 静态变量
    [1] 通过static关键字修饰,是属于类,实例成员属于对象,在这个类第一次加载的时候,这个类下面的所有静态成员会被加载。
    [2] 静态成员只被创建一次,所以静态成员只有一份,实例成员有多少个对象,就有多少份
    [3] 类加载的时候,所有的静态成员就会被创建在“静态存储区”里面,一旦创建直到程序退出,才会被回收。
    [4] 成员需要被共享的时候,方法需要被反复调用的时候,就可以把这些成员定义为静态成员。
    [5] 在静态方法中,不能直接调用实例成员,因为静态方法被调用的时候,对象还有可能不存在。
    [6] this/base 关键字在静态方法中不能使用,因为有可能对象还不存在。
    [7] 可以创建这个类的对象,制定对象的成员在静态方法中操作。
    [8] 在实例方法中,可以调用静态成员,因为这个时候静态成员肯定存在。
    [9] 非静态类可以包含静态的方法、字段、属性或事件;
    [10] 无论对一个类创建多少个实例,它的静态成员都只有一个副本;
    [11] 静态方法和属性不能访问其包含类型中的非静态字段和事件,并且不能访问任何对象的实例成员;
    [12] 静态方法只能被重载,而不能被重写,因为静态方法不属于类的实例成员;
    [13] 虽然字段不能声明为 static const,但 const 字段的行为在本质上是静态的。这样的字段属于类,不属于类的实例。
  • 静态方法
    [1] 静态方法是不属于特定对象的方法;
    [2] 静态方法可以访问静态成员;
    [3] 静态方法不可以直接访问实例成员,可以在实例函数调用的情况下,实例成员做为参数传给静态方法;
    [4] 静态方法也不能直接调用实例方法,可以间接调用,首先要创建一个类的实例,然后通过这一特定对象来调用静态方法。
  • 静态构造函数
    [1] 静态类可以有静态构造函数,静态构造函数不可继承;
    [2] 静态构造函数可以用于静态类,也可用于非静态类;
    [3] 静态构造函数无访问修饰符、无参数,只有一个 static 标志
    [4] 静态构造函数不可被直接调用,当创建类实例或引用任何静态成员之前,静态构造函数被自动执行,并且只执行一次
  • 什么时候适合用static修饰?
    1.当变量需要被共享时可以将变量定义为静态变量。
    2.当方法需要被反复调用时可以将方法定义为静态方法。
    3.当一个类中包含的成员都是静态时可以将类定义为静态类。

接口和抽象类

接口(Interface)是用来定义行为规范的,不会有具体实现,而抽象类除定义行为规范外,可以有部分实现,但一个类能实现多个接口,但只能继承一个父类
1、继承:接口支持多继承,抽象类不能实现多继承

2、表达的概念:接口用于规范,抽象类用于共性。抽象类是一类事物的高度聚合,那么对于继承抽象类的子类来说,对于抽象类来说,属于“是”的关系;而接口是定义行为规范,因此对于实现接口的子类来说,相对于接口来说,是“行为需要按照接口来完成”;

3、方法实现:对抽象类中的方法,即可以给出实现部分,也可以不给出;而接口的方法(抽象规则)都不能给出实现部分,接口中方法不能加修饰符;

4、子类重写:继承类对于两者所涉及方法的实现是不同的。继承类对于抽象类所定义的抽象方法,可以不用重写,也就是说,可以延用抽象类的方法;而对于接口类所定义的方法或者属性来说,在继承类中必须重写,给出相应的方法和属性实现;

5、新增方法的影响:在抽象类中,新增一个方法的话,继承类中可以不用作任何处理;而对于接口来说,则需要修改继承类,提供新定义的方法;

6、接口可以作用于值类型(枚举可以实现接口)和引用类型;抽象类只能作用于引用类型;

7、接口不能包含字段和已实现的方法,接口只包含方法、属性、索引器、事件的签名;抽象类可以定义字段、属性、包含有实现的方法;

8、接口可以用于支持回调(CallBack);抽象类不能实现回调,因为继承不支持;

如何选择:
1、看是否需要多继承,如果需要就只能使用接口;
2、看你在类里定义的方法是否需要有实现的代码,如果要,就使用抽象类;
3、使不同的类型有共同的特性的时候使用接口,因为它支持多继承;只想从一个类型继承出不同的行为的子类的时候使用抽象类,可以在基类里有代码实现;

从实现接口和现实抽象类的方法来看,接口是死的,抽象类是活的,当然实现接口的类是活的;

面向对象设计五大原则SOLID原则

  • 单一职责原则SRP
    表明一个类有且只有一个职责,它希望类型应当只具有一种功能或表示一种概念,这里应将功能理解为改变的原因。
    每一个类将负责单一的问题、任务或者它关注的点,这种方式你只需要改变相应的类,只有这个类需要再次测试。
    例如,数据库管理类应当只包括对数据库进行 CRUD 动作的方法,不应该包括其他方法,例如权限判断等。
    单一职责原则既可以用于类型(类、结构、接口),也可以用于方法。在撰写方法时,如果每个方法只专注于一件事,那么它的命名也就很简单,单元测试非常方便,其他开发者也可以很容易地理解这个方法内部的代码。
  • 开放封闭原则OCP
    一个类应该对扩展开放,对修改关闭
    如果你需要一些额外功能,你应该扩展这个类而不是修改它。使用这种方式,现有系统不会看到任何新变化的影响。同时,你只需要测试新创建的类。
  • 里氏替换原则LSP
    派生的子类应该是可替换基类的,也就是说任何基类可以出现的地方,子类一定可以出现
  • 接口隔离原则ISP
    类不应该被迫依赖他们不使用的方法,也就是说一个接口应该拥有尽可能少的行为,它是精简的,也是单一的。
  • 依赖倒置原则DIP
    表明一个方法应该遵从依赖于抽象(接口)而不是一个实例(类)的概念。依赖注入降低模块之间的耦合程度。如果你的汽车的定义依赖于具体的引擎和车轮,那么,你就无法更改引擎和车轮的类型。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值