前段时间,八期给我们讲设计模式学术交流,由于设计模式大家都学的不是很好,所以,我们九期听的也非常费力,就算不费力,也只限于弄明白理论上的了,也不是太会用。后来米老师又给我们讲,结合我们实际的项目,来讲设计模式,通过深刻的挖掘,和对比,使我们收获很大。其中对多问几个为什么,追根溯源等有了进一步的理解。
下来,我认真的思考过,为什么我们学习不好设计模式,为什么一直不会用,就算不合理的也用不上。一方面和我们对囫囵吞枣学习有误解,这个仅限于我们初级阶段的学习,而随着我们项目的实践,知识的运用,我们必须深刻的理解知识,学习触类旁通,必须在实践中弄懂知识之间的联系与区别,弄清楚知识的来龙去脉,这样才能举一反三,才能在项目中运用自如,这样才能走向高手的地位!
但是对于我现阶段的学习,我认为学习设计模式,必须先把设计模式的必备知识——面向对象的基础学习的很透彻,学习设计模式才会更容易些,因为设计模式就是为了更好的实现面向对象,而设计模式这些框架,就是很好的运用来搭配运用面向对象的基础知识。再次看面向对象的基础,感觉清晰很多,理解更深刻,总结一下。
先看这张图,大概说了下各部分之间的关系,可能有的地方不合理,但是为了比较,我也放到哪里了,有什么问题还请提出:
一,首先说类,这是面向对象最最基础的:
1,类的实例化很简单:
class Cat
{
Public string Shout()
{
renturn"喵";
}
}
Private void button1_Click(object sender,EventArgs e)
{
Cat cat=new Cat();//类的实例化
messageBox.show(cat.shout());
}
2,类的初始化:构造方法(又叫构造函数)
a,特点:构造方法与类同名,无返回值,也不需要void,在new时候调用。如果不写,则系统默认为空的构造方法。
b,例子:
Class Cat
{
private string name="";//声明Cat类的私有字符串变量
public Cat(string name)//定义Cat类的构造方法
{
this.name=name; //将参数赋值给私有变量
}
public string shout()
{
return"我的名字叫做" +name+"喵";
}
}
c,对于构造方法的继承,继承中给出!
3,类的属性和方法,大家应该都非常属性,这里我重点区分一下面向对象中类的修饰符:public,private,protected.
public:声明全局变量,也就是说整个项目都可以访问到。
private:声明私有变量,也就说只有这个类内部可以访问。
protected:声明局部保护变量,只有其继承类可以访问。
注意:在将类抽象时,需要将类中的private修饰符,变为protected,因为抽象类就是用来继承的。
二,封装:也就是每个对象都包含它们能进行操作所需要的所有信息。也是我们类,对象,抽象类等需要满足的。这样才会有一下几个优点:
1,良好的封装能够减少耦合;
2,类内部的实现可以自由的修改;
3,类具有清晰的对外接口。
三,继承:对于定义就不说了,
1,我们需要先记住这三句话:
a,子类拥有父类的非private的属性和功能;
b,子类具有自己的属性和功能,也就说子类可以扩展父类没有的属性和功能;
c,子类还可以以自己的方式实现父类的功能(方法重写)。
2,a,构造方法:在子类中用base关键字调用父类的构造方法。
b,虚方法:为了使子类能够完全接替父类方法,有些必须要声明为虚方法,用virtual关键字声明,这样不同的子类就可以通过方法重写,用自身的方式实现父类的方法了。
c,抽象类,就是类的抽象,例如,人类是对每个具体人的抽象,猫类是对每个具体猫的抽象,而动物类就是对人类和猫类的抽象。用abstract class 类名来声明。里边的虚方法也加上abstract就成了抽象方法了。
d,接口,声明用interface,里边的方法,属性能有修饰符,因为不能实例化。是将公共方法和属性组合起来,供其他类实现这些的一个集合。
例子:
类Animal
class Animal//声明一个父类 ,加上abstract就是抽象类了。
{
protected string name = "";//声明类的的私有字符串变量name,用protected
public Animal(string name)//构造方法,参数是输入一个字符串
{
this.name = name;
}
public Animal()//将构造方法重载
{
this.name = "无名";
}
protected int shoutNum1 = 3;
public int ShoutNum1
{
get//get表示外界调用属性的值
{
return shoutNum1;
}
set//set表示外界可以给属性的赋值
{
shoutNum1= value;
}
}
public virtual string Shout()//用virtual定义虚方法,被子类重写,换位abstract为抽象方法了
{
return"";
}
}
接口:
interface IChange
{
string ChangeThing(string thing);
}
声明类来继承上边的父类和接口:
class Cat:Animal,Ichange
{
public MachineCat():base()//构造方法的继承
{
}
public MachineCat():base(name)//构造方法的继承
{
}
public override string Shout()//虚方法的重写
{
return"我的是"+name+" 喵";
}
public string ChangeThing(string thing)//接口方法的实现
{
return "我是猫,我可以变出:"+ thing;
}
}
备注:a,虚方法和抽象方法的区别:虚方法是写在普通类里的供子类重写的方法,而抽象方法,可以看做是抽象类里边的虚方法。
b,抽象类和接口的区别:1,从继承角度上来说,继承抽象类的子类,可以重写抽象类的方法,可以拓展功能;而继承接口,也就是实现接口,必须完全实现接口的方法; 2,从数量上说,子类只能继承一个抽象类,而类可以死实现一个或好几个接口; 3,从生成角度上看,抽象类是由对象抽象出类,由类抽象出抽象类的,为自底向上的形成,而接口,是自己制定方法,由子类去实现的,为自顶向下的形成。
四,多态,表示不同的对象可以执行相同的动作,但要通过它们自己的实现代码来执行。
1,实现多态的两种根本方法:方法重写(override)和方法重载,这两个上边代码都出现过。
2,两者的区别:方法重写,一般是将虚方法,抽象方法等,在子类中进行实现,方法名,参数等都一样。 方法重载,是在一个类中,为了实现多态,将某些方法,进行改变参数或者返回值,而方法名不变,来实现重载。 而编译和运行来看,方法重写是在运行时进行动态绑定调用,而方法重载则是在编译时。
3,对于数组和集合,为什么我放到这里呢?因为多态么,多个对象,需要我们用数组或集合来实现,我以前写过篇博客,有内容,看连接:C#语言知识汇总
4,两者的优缺点:数组优点,在内存中存储,很容易从头到尾遍历元素,可以快速修改元素。 缺点:必须要限制数组的长度,两个元素直接添加元素也比较困难。 集合呢?优点:使用大小可以根据需要动态的增加删除元素,非常方便。缺点:就是集合为不类型安全的,输入什么类型都可以,容易引起错误。
5,泛型呢?就是为了弥补上边集合缺点而设计的。也就是来声明集合的变量的。此时集合成为泛型集合。一般在集合后加<变量类型>。看个例子:
IList<Animal> arrayAnimal;//声明一个泛型集合变量,用接口Ilist,注意Ilist<Animal>表示此集合变量只能接受Animal类型 ,也可以直接用List<Animal>
private void button3_Click(object sender, EventArgs e)//动物报名按钮,
{
//arrayAnimal = new Animal[5];//实例化最多可以可报名5个的动物数组对象
arrayAnimal = new List<Animal> ();//实例化List对象
arrayAnimal.Add(new Cat ("小花"));//报名分别是猫和狗
arrayAnimal.Add( new Dog("阿毛"));
arrayAnimal.Add ( new Dog("小黑"));
arrayAnimal.Add(new Cat("娇娇"));
arrayAnimal.Add( new Cat("咪咪"));
MessageBox.Show(arrayAnimal.Count.ToString());//打印出我们添加的个数
arrayAnimal.RemoveAt(1);//这里还可以删除我们多添加的。
}
五,委托:是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为。声明委托的关键字。
事件:发生其他类或对象关注的事情时,类或对象可通过事件通知它们。声明事件的关键字event。
委托例子:
Class Cat//声明一个猫类
{
private string name;
public Cat(string name)
{
this.name=name;
}
public delegate void CatShoutEventHandler();//声明一个委托
public event CatShoutEventHandler CatShout;//声明事件CatShout它的事件类型是上边声明的委托
public void Shout()
{
Console.WriteLine("喵,我是{0}.",name);
if (CatShout!=null)
{
CatShout();//表明当执行Shout()方法时,如果CatShout中有对象登记事件,则执行CatShout()!
}
}
}
Class Mouse
{
private string name;
public Mouse(string name)
{
this.name=name;
}
public void Run()//逃跑的方法
{
Console.WriteLine("老猫来了,{0}快跑",name);
}
}
Static void Main(string[] args)
{
Cat cat =new Cat("Tom");
Mouse mouse1=new Mouse("John");
Mouse mouse2=new Mouse("Jack");
cat.CatShout+=new Cat.CatShoutEventHandler(mouse1.Run);//将Mouse的Run方法通过实例化委托Cat.CatShoutEventHandler登记到Cat的事件CatShout当中。
cat.CatShout+=new Cat.CatShoutEventHandler(mouse2.Run);
cat.Shout
Console.Read();
}
委托也就是将Mouse的方法,添加到猫叫当中,当猫叫时,直接通过老鼠,使其发生run的动作。
事件+委托,可以更好的完善委托,使我们的程序更加合理。EventArgs是我们代码经常见的,它是包含事件数据的类的基类。我们来看上边的例子加上事件后的写法,看是不是方便了:
public classCatShoutEventArgs:EventArgs//声明一个事件类,继承EventArgs
{
private string name;
public string Name
{
get{return name;}
set {name=value;}
}
}
Class Cat//声明一个猫类
{
private string name;
public Cat(string name)
{
this.name=name;
}
public delegate voidCatShoutEventHandler(object sender,CatShoutEventArgs args);//声明一个委托,此时有两个参数。注意和上边的不同
public eventCatShoutEventHandler CatShout;//声明事件CatShout它的事件类型是上边声明的委托
public void Shout()
{
Console.WriteLine("喵,我是{0}.",name);
if (CatShout!=null)
{
CatShoutEventArgs e =new CatShoutEventArgs();
e.Name=this.name;
CatShout(this,e);//当事件触发时,通过所有登记过的对象,并将发送通知,以及需要的数据传递过去。
}
}
}
ClassMouse
{
private string name;
public Mouse(string name)
{
this.name=name;
}
public void Run(object sender,CatShoutEventArgs args)//逃跑的方法
{
Console.WriteLine("老猫来{0}了,{1}快跑",args.Name,name);
}
}
客户端不变,这样猫的名字就传过来了,更加合理化了。这就是事件在委托中的运用。
对于委托和观察者模式:相同点就是,都是被动变为主动,使被委托的人,被通知的人,主动来接受信息,主动来进行各种动作。不同点:其实就是观察者模式将委托很好的运用,委托为观察者的核心。委托只是一种方法,而观察者为一种结构。
综上为面向对象的基础,感觉这次理解更加深刻了,剩下就是利用这些东西来学习设计模式!如何能够更好的学习设计模式,领会它的本质,精华,才是更本!