您的位置:首页 > 其它

面向对象知识总结

2013-11-21 22:28 197 查看
面向对象总结
在软件开发中,我们应该遵循最基本的高内聚、低耦合的原则,也就是说程序中各个部分相互之间的依赖性越低越好,而它们之间的联系越紧密越好。面向对象设计思想可以很好的体现这一原则。我们可以从不同的事物中找出它们的共同点,然后抽象成一个类,这一类的事物拥有自己最基本的特点和行为。比如说,我们可以从各个不同的人这一实体中抽象出人类,所有人类的共同特点是都有自己的名字和年龄等,共同的行为是都要吃饭、都要睡觉。通过面向对象思想,我们可以用属性(或字段)表示类的特点,用方法表示类的行为。这样,把属性和方法封装到一个类中,当使用时,创建这个类的对象,通过对象来访问类的属性和方法。

一、类和对象

类和对象是面向对象思想中的两个最基本的概念。对象是客观存在的实例,拥有自己的属性和方法。类是对具有相同的属性和方法的一组对象的描述。我们使用class关键字创建一个类,使用new关键字和类的构造方法创建这个类的实例。如下,创建一个人类和这个类的实例:

Class Person

{

public string name;

public void Eat(){ }

public Person(){ }

}

Person p = new Person();

类的构造方法是专门用于初始化类,创建这个类的实例。构造方法的方法名和它所在的类的类名相同,但不可以有返回类型,也就是连void都不能有。每创建一个类,系统都会自动为它创建一个无参的构造方法。我们也可以为类添加有参构造方法,但添加有参方法之后,系统不再为该类自动创建无参构造方法,如果我们仍然需要用无参构造方法,就必须自己手动创建。

面向对象设计思想有三大特性——封装、继承和多态。它最主要的用法是多态,封装和继承都是为了实现多态。

二、封装

软件设计有一个原则就是封装变化点,把程序中经常变化的部分封装起来,可以降低类与类之间的耦合性。

为了提高代码的可重用率,我们会把部分代码封装起来,形成一个方法。当需要使用这个方法的功能时,对于有参方法,我们只需根据要求传入参数就可以实现(),对于无参方法,直接或通过类的对象调用。这样就大大提高了代码的重用性。
在一个类中,为了保证数据的安全性,我们会把存储这个数据的变量作为字段(字段是私有的),然后把这个字段封装成一个公共的属性,提供外部访问的接口。在这个属性中,我们就可以使用set访问器来限定数据的范围,确保它不会超出预料。如:人的年龄不能负,银行卡里的存款也不能为负。
Class Person
{
private int age;
public int Age
{
get { return age;}
set
{
If(value< 0 || value >200)
{
age= 0;
}
else
{
age= value;
}
}
}
}
封装的使用总结如下:

1. 私有化数据成员,提供公开的对外访问接口。

2. 把一个类封装到一个命名空间中,保证各类不会重名。

3. 把类的代码封装到一个程序集中。

4. 把代码段封装到一个方法中,外部需要时可以直接调用而无需在意方法内部是如何实现的。

5. 将变量和方法封装到类中。

三、继承

继承描述的是类与类之间的一种关系。在创建类的过程中,我们可以发现,有一些类的属性和方法相同,比如Student类和Teacher类,都有姓名Name和年龄Age属性,都有吃饭的方法。每创建一个这样的类,就要给它一个相同的成员,这不免让人烦索,会造成代码的冗余。我们可以提取这些类里面相同的成员,形成一个新的类,让原来的类可以访问这个新类里面的成员,这样被提取成员的类就是子类,形成的新类就是这些子类的父类。子类可以继承父类的成员。如,从Student类和Teacher类中提取出Name和Age作为新类Person里面的成员,让Student和Teacher继承自Person,这样,Student和Teacher都可以拥有Name和Age属性,实现代码的重用。

继承有两大特性,即单根性和传递性。单根性要求每个类至多只能继承自一个类,但它可以实现多个接口。传递性要求一个类的子类可以访问这个类的父类的成员。在类的继承关系中,如果创建一个子类对象,则会先调用这个子类的父类的构造方法,然后再调用子类本身的构造方法。默认情况下,创建子类对象时会调用父类的无参构造方法,我们也可以使用base关键字指定调用父类的有参构造方法。在本类中,我们还可以使用this关键字指定调用自己的构造方法。

classPerson

{

public Person()

{

Console.WriteLine("Person无参");

}

public Person(string name)

{

Console.WriteLine("Person有参");

}

}

class Student : Person

{

public Student()

{

Console.WriteLine("Student无参");

}

public Student(string name)

: base(name) //使用base关键字调用父类的有参构造函数

{

Console.WriteLine("Student一个参数");

}

public Student(string name, string sex)

: this(name) //使用this关键字调用本类的一个参数的构造函数

{

Console.WriteLine("Student两个参数");

}

}

当定义类时,如果没有明确为这个类指定父类,则它默认继承自object类。我们可以使用base关键字调用某个类的父类的成员。

四、多态

使用面向对象思想,最主要的目的是为了实现多态。封装和继承都是多态的基础。使用父类变量指向子类对象,当不同的子类对象调用父类中的同一个方法时会呈现出不同的结果,这种现象就是多态。实现多态,我们首先要使用virtual关键字修饰父类方法,使之成为虚方法,然后在子类中使用override关键字重写父类的虚方法。使用virtual修饰的方法和使用override修饰的方法的方法签名必须相同。

class Person

{

public virtual void SayHello()

{

Console.WriteLine("PersonSH");

}

}

class Student : Person

{

public override void SayHello()

{

Console.WriteLine("StudentSH");

}

}

class Teacher : Person

{

public override void SayHello()

{

Console.WriteLine("TeacherSH");

}

}

如果创建一个对象Person p =new Student(); ,则p.SayHello(); 语句会执行Student类里面的SayHello方法,即输出Student SH。

在多态的思想中,有一个很重要的里氏替换原则,即父类变量可以指向子类对象,反之子类变量则不能指向父类对象。在使用多态时,我们可以使用is关键字判定变量的类型。

五、抽象类

实现多态不仅可以使用虚方法,还可以使用抽象方法。抽象方法必须存在于抽象类中。它的使用方法和virtual关键字差不多,只不过要把virtual关键字改为abstract,并且不能有方法体及大括号。抽象类是不能实例化的类,在抽象类中的抽象成员必须全部被它的子类实现,除非它的子类也是抽象类。

abstract class Person

{

public abstract void SayHello()

{

Console.WriteLine("Person SH");

}

}

使用虚方法virtual和抽象方法abstract的区别是:

1.虚方法必须要有实现(即有大括号),而抽象方法不能有实现,不能有方法体,连大括号都不能有,直接在方法后面加分号。

2.虚方法在它的子类中可以被重写,也可以不被重写,但抽象方法必须在它的子类中重写,除非它的子类也是抽象类。

3.使用虚方法的类可以实例化,但有抽象方法的抽象类不能被实例化。

六、接口

接口是一种规范,它是为了更好地实现多态。在面向对象编程中,我们提倡面向接口编程。面向接口编程意味着,在开发系统时,主体架构使用接口,接口构成系统骨架,这样,我们就可以通过更换实现接口的类来实现系统的更换。

定义接口时,要使用interface关键字,并且接口名要以大写字母I开头。在接口里面,不可以有字段,只能有属性、方法、索引器和事件。接口里面的所有成员都默认为public,但在定义的时候,我们不能给它们显式添加访问修饰符。一个类实现一个接口,要求这个类实现这个接口里面的所有方法。接口实现多态,是以接口类型的变量指向实现该接口的类的对象。一个子类只能继承自一个父类,但可以实现多个接口。当类同时继承了父类和实现接口时,父类要写在冒号后面的第一位,即所有继承的接口之前。如下:

interface IDoHomeworkabel

{

void DoHomework();

}

class Student : Person, IDoHomeworkabel

{

public override void SayHello()

{

Console.WriteLine("StudentSH");

}

public void DoHomework()

{

Console.WriteLine("Student DoHomework!");

}

}

使用时,声明IDoHomeworkablestu = new Student(); 然后用stu调用实现的方法就行,也可以使用Student类型的变量来调用这个方法。

我们也可以显式地实现一个接口,显式实现接口的方法必须通过声明该接口类型的变量指向实现该接口的类的对象的方式来访问。显式实现接口的方法前面有限定符,指定了这个方法是哪个接口的,其它类型的变量都不能访问。它没有访问修饰符,默认为private,并且不可以修改。

interface IGotoschoolable

{

void GoToSchool();

}

class Student : Person, IDoHomeworkabel, IGotoschoolable

{

public override void SayHello()

{

Console.WriteLine("StudentSH");

}

public void DoHomework()

{

Console.WriteLine("Student DoHomework!");

}

void IGotoschoolable.GoToSchool()

{

Console.WriteLine("Go toSchool!");

}

}

在使用显式实现的方法时,只能通过声明IGotoschoolablestu = new Student(); ,然后用stu调用实现的方法,此时,不能使用Student类型的变量来访问这个方法,这个方法只能被IGotoschoolable类型的变量访问。

一个接口也可以继承自另一个接口,接口之间的继承也具有传递性。一个接口最好只实现一个功能,不要实现多个功能,否则会造成接口污染。

接口和抽象类的异同:

1. 抽象类只能在同一个类型的类中实现多态,而接口可以在不同类型的类中实现多态。

2. 抽象类和接口都不能实例化。

3. 抽象类要求继承该类的子类必须实现它的抽象方法,除非它的子类也是抽象类;接口同样也要求实现该接口的类实现接口中的所有方法。

七、设计模式

设计模式是人们在长期的开发过程中,对一些特定场合使用特定的方法,进行的经验的总结。设计模式有很多,最简单的有简单工厂设计模式和单例设计模式。

简单工厂设计模式要求工厂根据给定的原料来生产相应的产品,即工厂类根据用户传入的参数,动态决定该创建哪一个类的实例。这些能够创建实例的类都拥有一个共同的父类。

单例设计模式要求在类的外部只能创建一个该类的实例。我们可以把该类的构造函数私有化,这样在外部就不能通过new关键字来创建对象。但是,在类的内部,我们需要用一个静态的私有变量来保存该类的唯一实例。然后还要用一个公共的静态方法来获取这个唯一实例。这样在类的外部就可以通过类名.方法名的方式取得该类的唯一实例。

八、静态

静态与多态是相冲突的,使用static关键字来定义。我们可以用静态static来修饰类,数据成员和方法成员。静态类不能被实例化,静态类中只能有静态成员,但静态成员也可以存在于普通类中。静态类有一个静态的构造方法,用static来修饰,后面直接跟静态类名。在同一个类的普通方法中,可以直接访问静态成员,但在静态方法中,却不能直接访问非静态成员,需要通过对象来访问非静态成员。

当我们第一次使用静态类时,会一次性将所有的数据成员加载到内存中,由CLR调用静态构造方法完成静态类的初始化。静态成员在运行时,会被加载到静态存储区,并且只有一个固定的内存地址,直到程序运行结束时才会被释放。因此不宜多用静态类,因为静态类在初始化的时候会占用大量的内存资源。

用sealed关键字修饰的类不能被继承,修饰的方法也不能被重写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: