C#大话设计模式学习总结
如有雷同,不胜荣欣,如转载,请注明
C#大话设计模式学习总结
一、工厂模式
面向对象的三个特性:封装,继承和多态
1.封装
Class Operate
{
privatedouble _numberA;
privatedouble _numberB;
publicdouble NumberA
{
get{return_numberA;}
set{_numberA= value;}
}
publicdouble _numberB
{
get{return_numberB;}
set{_numberB= value;}
}
}
2.继承
//父类
Class Operation
{
privatedouble _numberA;
privatedouble _numberB;
publicdouble NumberA
{
get{return_numberA;}
set{_numberA= value;}
}
publicdouble _numberB
{
get{return_numberB;}
set{_numberB= value;}
}
//父类的虚方法
publicvirtual double GetResult()
{
doubleresult = 0;
returnresult;
}
}
//加法运算子类
Class OperationAdd:Operation
{
publicoverride double GetResult()
{
doubleresult = 0;
result= NumberA + NumberB;
returnresult;
}
}
//减法运算子类
Class OperationSub:Operation
{
publicoverride double GetResult()
{
doubleresult = 0;
result= NumberA - NumberB;
returnresult;
}
}
//乘法运算子类
Class OperationMul:Operation
{
publicoverride double GetResult()
{
doubleresult = 0;
result= NumberA * NumberB;
returnresult;
}
}
//除法运算子类
Class OperationDiv:Operation
{
publicoverride double GetResult()
{
doubleresult = 0;
result= NumberA / NumberB;
returnresult;
}
}
3.多态 :允许将子类类型的指针赋值给父类类型的指针
接口
1、C#接口的作用 :
C# 接口是一个让很多初学C#者容易迷糊的东西,用起来好像很简单,定义接口,里面包含方法,但没有方法具体实现的代码,然后在继承该接口的类里面要实现接口 的所有方法的代码,但没有真正认识到接口的作用的时候就觉得用接口是多此一举,当然你这样想那是绝对绝对错误的,比尔盖茨的微软请的员工都是比盖茨还聪明 的人,他们的C#能添这样的多足吗?!关于接口的作用,网上有一位就真的深入浅出给我们做了很好理解的分析。
我们定义一个接口
public interface IBark
{
void Bark();
}
再定义一个类,继承于IBark,并且必需实现其中的Bark()方法
public class Dog:IBark
{
public Dog(){}
public void Bark()
{
Consol.write("汪汪");
}
}
然后,声明Dog的一个实例,并调用Bark()方法
Dog 旺财=new Dog();
旺财.Bark();
试想一样,若是想调用Bark()方法,只需要在Dog()中声明这样的一个方法不就行了吗,干什么还要用接口呢.因为接口中并没有Bark()具体实现.真的实现还是要在Dog()中.那么使用接口不是多此一举吗?
还 有人是这样说的:从接口的定义方面来说,接口其实就是类和类之间的一种协定,一种约束.还拿上面的例子来说.所有继承了IBark接口的类中必需实现 Bark()方法.那么从用户
(使用类的用户)的角度来说,如果他知道了某个类是继承于IBark接口,那么他就可以放心大胆的调用Bark()方法,而 不用管Bark()方法具体是如何实现的.比如,我们另外写了一个类.
public class Cat:IBark
{
public Cat(){}
public void Bark()
{
Consol.write("喵喵");
}
}
当用户用到Cat类或是Dog类的时候,知道他们继承于IBark,那么不用管类里的具体实现,而就可以直接调用Bark()方法,因为这两个类中肯定有关于Bark()方法的具体实现.
如 果我们从设计的角度来看.一个项目中用若干个类需要去编写,由于这些类比较复杂,工作量比较大,这样每个类就需要占用一个工作人员进行编写.比如A程序员 去定Dog类,B程序员去写Cat类.这两个类本来没什么联系的,可是由于用户需要他们都实现一个关于"叫"的方法.这就要对他们进行一种约束.让他们都继承于IBark接口,目的是方便统一管理.另一个是方便调用.当然了,不使用接口一样可以达到目的.只不过这样的话,这种约束就不那么明显,如果这样类 还有Duck类等等,比较多的时候难免有人会漏掉这样方法.所以说还是通过接口更可靠一些,约束力更强一些.
2、C#中接口的深入浅出:
通过学习对C#中接口的作用有了更进一步的理解,拿出来跟大家分享一下,有说的不对的地方请大家指教。
假设我们公司有两种程序员:VB程序员,指的是用VB写程序的程序员,用clsVBProgramer这个类表示;Delphi程序员指的是用 Delphi写程序的程序员,用clsDelphiProgramer这个类来表示。每个类都有一个WriteCode()方法。定义如下:
class clsVBProgramer()
{
....
WriteCode()
{
//用VB语言写代码;
}
....
}
class clsDelphiProgramer()
{
....
WriteCode()
{
//用Delphi语言写代码;
}
....
}
现在公司来了一个项目,要求派某个程序员写一个程序。
class clsProject()
{
....
WritePrograme(clsVBProgramer programer)
//用VB写代码
{
programer.WriteCode();
}
WritePrograme(clsDelphiProgramer programer)
//重载方法,用Delphi写代码
{
programer.WriteCode();
}
......
}
在主程序中我们可以这样写:
main()
{
clsProject proj=new clsProject; //如果需要用VB写代码
clsVBProgramer programer1=new clsVBProgramer;
proj.WritePrograme(programer1); //如果需要用Delphi写代码
clsDelphiProgramer programer2=new clsDelphiProgramer;
proj.WritePrograme(programer2);
}
但是如果这时公司又来了一个C#程序员,我们怎么改这段程序,使它能够实现用 C#写程序的功能呢?我们需要增加一个新类clsCSharpProgramer,同时在此clsProject这个类中要再次重载
WritePrograme(clsCSharpProgramer programer)方法。这下麻烦多了。如果还有C程序员,C++程序员,JAVA程序员呢。麻烦大了!
但是如果改用接口,就完全不一样了: 首先声明一个程序员接口:
interface IProgramer()
{
WriteCode();
}
然后声明两个类,并实现IProgramer接口:
class clsVBProgramer():IProgramer
{
....
WriteCode()
{
//用VB语言写代码;
}
....
}
class clsDelphiProgramer():IProgramer
{
....
WriteCode()
{
//用Delphi语言写代码;
}
....
}
对clsProject这个类进行一下修改:
class clsProject()
{
....
WritePrograme(IProgramer programer)
{
programer.WriteCode();
//写代码
}
......
}
main()
{
clsProject proj=new clsProject;
IProgramer programer; //如果需要用VB写代码
programer=new clsVBProgramer;
proj.WritePrograme(programer); //如果需要用Delphi写代码
programer=new clsDelphiProgramer;
proj.WritePrograme(programer);
}
如果再有C#,C,C++,JAVA这样的程序员添加进来的话,我们只需把它们相关的类加进来,然后在main()中稍做修改就OK了。扩充性特别好!
另外我们如果把clsProject这个类封成一个组件,那么当我们的用户需要要扩充功能的时候,我们只需要在外部做很小的修改就能实现,可以说根本就用不着改动我们已经封好组件!是不是很方便,很强大!
二、策略模式
策略模式涉及三个角色
1.环境(Context)角色持有一个Strategy类的引用。
2.抽象策略(Strategy)角色这是一个抽象角色,通常有一个接口或抽象类实现,此角色给出所有的具体策略类所需的接口。
3.具体策略(Concrete Strategy)角色包装了相关的算法和行为。
依赖注入(dependency injection)是需要IoC容器提供的,比如spring.net.
声明一个动物对象,名称animal,然后将animal实例化成猫类的对象
方法一:实例化一个类Animal animal = new Cat();
方法二:using System.Reflection;
假设当前程序集是AnimalSystem,名称空间也是AnimalSystem
那么使用反射技术实例化一个类就是Animal animal = (Animal)Assembly.Load("AnimalSystem").CreateInstance("AnimalSystem.Cat");
关键是:Assembly.Load("程序集名称").CreateInstance("名称空间.类名称")
设计模式的几大设计原则:
1.单一职责原则是指对于一个类而言,应该仅有一个因其他变化的原因。
2.开放-封闭原则是说对扩展开发,对修改关闭,具体说就是我们设计一个模块时,使该模块可以不再被修改的前提下被扩展。
3.依赖到转原则是抽象不应该依赖细节,细节应该依赖于抽象。说白了就是要针对接口编程,不针对实现编程
4.迪米特法则LoD,也叫最少知识原则,简单的说,就是如果两个类不必彼此直接通信,那么这两个类就不应该发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
5.门面模式或外观模式要求一个子系统的外部和其内部的通信必须通过一个统一的门面Facade对象进行。门面模式提供一个高层次的接口,使得子系统更容易使用。
门面模式图解
Facade门面角色:客户端可以调用这个角色的方法。此角色知晓相关的(一个或多个)子系统的功能和责任,在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统中去。
subsystem子系统角色:可以同时有一个或多个子系统,每一个子系统都不是一个单独的类,而是一个类的集合,每一个子系统都可以直接被客户端调用,或者被门面角色调用,子系统并不知道门面的存在,对于子系统而言,门面仅仅是一个客户端而已。
三层架构
1.UI层(表示层,界面层,表现层) UI
2.业务逻辑层(Business Logic Layer)BLL
3.数据访问层(Data Access Layer)DAL
C#设计模式
创建型模式:1.简单工厂模式,2.工厂方法模式,3.抽象工厂模式,4.单件模式,5.生成器模式,6.原型模式
创建型模式是创建对象而不是直接实例化对象,这会使程序在判断给定情况下创建哪一个对象时更为灵活。
结构型模式:7.适配器模式,8.桥接模式,9.组合模式,10.装饰模式,11.外观模式,12.享元模式,13.代理模式
结构型模式可以将一组对象组合成更大的结构,例如复杂的用户界面和报表数据。
行为型模式:14.职责链,15.命令模式,16.解释器模式,17.迭代器模式,18.中介者模式,19.备忘录模式,20.观察者模式,21.状态模式,22.策略模式,23. 模板方法模式,24.访问者模式
行为型模式定义系统内对对象间的通信,以及复杂程序中的流程控制。
一个常被引用的模式是Smalltalk(Krasmer and Pope 1988)的模型-视图-控制器(Model-View-Controller)框架
数据模型:包括程序的计算部分
视图:表示用户界面
控制器:定义用户和视图的交互方式
对象组合:
C#中的字符是16位的宽度,可以表示非拉丁语言中的所有字符,它是使用一种双字节吗的字符编码系统
C#和java的区别:
1.许多系统对象都有相同的方法名,只是在大小写形式上有区别。
2.C#不提供throws关键字,该关键字使编译器你是否捕获了一个方法抛出的异常。
3.C#对布局管理器有更多的限制,因为他是以Windows系统为中心的,大多数时候采取的是图形元素的绝对位置。
4.C#允许运算符重载。
5.C#引进了代理和索引器的思想。
6.C#有枚举类型。
7.C#有不安全模式,在这种模式下可以使用指针。
8.必须专门声明一个方法能被覆盖及一个方法能覆盖另一个方法。
9.不能通过声明来区别继承和接口实现,它们的声明方式是一样的。
10.switch语句允许使用字符串变量,如果变量没有被匹配,必须有一个默认情况,否则会出现错误,break语句是必需的。
11.布尔类型在C#中为bool,在java中为boolean。
C#代理:
是一个类方法的原型,既可以是静态也可以是来自某个类实例,可以将代理声明为一种类型声明
private delegate stringfTxDelegate(string s);
fTxDelegate ftx; //代理变量
public class capital
{
publicstring fixText(string s)
{
returns.ToUpper();
}
}
public class Lower
{
publicstatic string fixText(string s)
{
returns.ToLower();
}
}
把fixText方法赋给一个代理变量
...
ftx = new fTxDelegate(newcapital().fixText);
...
ftx = newfTxDelegate(Lower.fixText);
C#索引器:
public class BitList
{
privateint number;
publicBitList(string $num)
{
number= Convert.ToInt32($num);
}
publicint this[int index]
{
get
{
intval = number>>index;
returnval & 1;
}
}
}
C#重载运算符:
public static Complex operator+(Complex c1,Complex c2)
{
returnnew Complex(c1.real + c2.real,c1.imaginary + c2.imaginary);
}
namespace CSharpPats
{
publicclass Rectangle
{
privateint x,y,w,h;
protectedPen rpen;
publicRectangle(int x_,int y_,int w_,int h_)
{
x= x_
y= y_;
w= w_;
h= h_;
rpen= new Pen(Color.Black);
}
publicvoid Draw(Graphics g)
{
g.DrawRectangle(rpen,x,y,w,h);
}
}
}
CSharpPats.Rectangle rect;
private void Init()
{
rect= new CSharpPats.Rectangle(10,20,70,100);
}
public Form1()
{
InitializeComponent();
Init();
}
pic框画图事件
private void pic_Paint(objectsender,PaintEventArgs e)
{
Graphicsg = e.Graphics;
rect.Draw(g);
}
下面需要创建一个square类
namespace CSharpPats
{
publicclass Square:Rectangle
{
publicSquare(int x,int y,int w):base(x,y,w,w)
{
...
}
}
}
public 公共的,都能访问
private 只能在该类内部访问
protected 只能在该类及派生类里访问
如果基类中有一个方法,而想在派生类中覆盖它,应该把基类中的方法声明为virtual,它的意义是让派生类中具有同样名字和参数标识的方法被调用,而不是调用基类中的方法。然后再派生类中必须用override关键字声明该方法。
如果基类中方法没有声明为virtu时,可以使用另一种期待基类中方法的方式,就是在派生类中声明方法时使用new关键字,这样做能有效地隐藏基类中同一名字(与参数无关)的方法,这种情况下,不能在派生类中调用基类中的方法,而且必须把所有的代码都放在替换方法中。
eg:public new void Draw(Graphicsg)
{
g.DrawRectangle(rpen,x,y,w,h);
g.DrawRectangle(rpen,x+ 5,y + 5,w,h);
}
C#接口:
本质上是一个规约,即一个类包含接口所描述的所有方法,接口声明方法的签名,不包含方法主体。
如果一个类实现了一个接口,就要提供接口中每一个方法的实现过程
C#抽象类:
声明一个或多个没有实现的方法,如果把一个方法声明为抽象方法,那么也需要把类声明为抽象的。
不能创建抽象类的实例,只能创建实现了抽象方法的派生类的实例
public abstract class Shape
{
...
publicShape(int x,int y,int w,int h)
{
...
}
public abstract void Draw(Graphlics g)
{
...
}
}
public class Rectangle:Shape
{
publicRetangle(int x,int y,int w,int h):base(x,y,w,h)
{
}
publicoverride void Draw(Graphics g)
{
...
}
}
接口和抽象类的比较:
1.创建一个接口就是创建了一个或多个方法的定义。
2.每个实现该接口的类中必须实现这些方法。
3.系统不会生成任何默认的方法代码,必须自己写代码实现。
4.提供了一种让一个类成为两个类的子类的方式:一个是继承,一个是来自子接口。
5.创建一个抽象类就是创建了这样一个基类,它可能有一个或多个完整的、可以工作的方法,但至少有一个方法未实现并声明为抽象的。
6.不能实例化一个抽象类,必须从它派生出类,这些类包含了抽象方法的实现过程。
7.如果一个抽象类的所有方法在基类中都未实现,它本质上就等同于一个接口。但限制条件是:一个类不能从它继承,也不能继承其他类层次结构,而是用接口可以这样做。
8.抽象类的作用是对派生类如何工作提供了一个基类定义、允许程序员在不同的派生类中填充这些实现过程。
9.创建一种带空方法的基类,这些空方法可以保证所有的派生类都能够编译,但是每个事件的默认操作是根本什么都不做。
C#数组、文件和异常
数组:
int[] x = new int[10];
float[] xy = new float[10];
集合对象:
ArrayList arrList = newArrayList();
HashTable
HashTable hash = new HashTable();
hash.Add("fred","freddy");
SortedList
SortedList sortedList = newSortedList();
sortedList.Add("sam","sammy");
Stack(堆栈)
Queue(队列)
C#文件
File对象都是静态的,不能用new实例化,而是直接使用
File.Exists("文件名");
File.Delete("文件名");
StreamReader ts =File.OpenText("文件名");
FileStream fs =File.OpenRead("foo2.any");
File.FileExists(filename) 若文件存在,则为true
File.Delete(filename) 删除文件
File.AppendText(string) 追加文本
File.Copy(fromFile,toFile) 拷贝一个文件
File.Move(fromFile,toFile) 移动文件,删除旧的文件
File.GetExtension(filename) 返回文件的扩展名
File.HasExtension(filename) 若文件有扩展名,则为true
读文本文件
StreamReader sr =File.OpenText("foo1.txt");
string s = sr.ReadLine();
写文本文件
StreamWriter sw =File.CreateText("foo3.txt");
sw.WriteLine("Hellofile");
或
StreamWriter sw = newStreamWriter("foo3.txt",true);
检测文件末尾
1.查找空null异常
2.查找数据流的末尾
eg:
private StreamReader sr;
private bool eof;
public String ReadNextLine()
{
strings = sr.ReadLine();
if(s== null)
{
eof= true;
}
returns;
}
public bool fEof()
{
returneof;
}
另一种保证读数据不会超过文件末尾的方法是:使用Stream的Peek方法在都数据前先查看一下,Peek方法返回文件中下一个字符的ASCII码,如果没有字符则返回-1
eg:
private StreamReader sr;
private bool eof;
public String ReadNextLine()
{
strings = "";
if(sr.Peek()> 0)
{
s= sr.ReadLine();
}
else
{
eof= true;
}
returns;
}
csFile类
public class csFile
{
privatestring fileName;
StreamReadersr;
StreamWritersw;
privatebool opened,writeOpened;
publiccsFile()
{
Init();
}
privatevoid Init()
{
opened= false;
writeOpened= false;
}
publiccsFile(string file_name)
{
fileName= file_name;
Init();
}
}
打开读数据的文件的方法:1.一个方法包含了文件的名字,2.将文件名做为参数。
public bool OpenForRead(stringfile_name)
{
fileName= file_name;
try
{
sr= new StreamReader(fileName);
opened= true;
}
catch(FileNotFoundExceptione)
{
returnfalse;
}
returntrue;
}
public string ReadNextLine()
{
returnsr.ReadLine();
}
打开写数据的文件的方法,并向其中写入若干行文本。
public void WriteNextLine(strins)
{
sw.WriteLine(s);
}
public bool OpenForWrite()
{
returnOpenForWrite(fileName);
}
public bool OpenForWrite(stringfile_name)
{
try
{
sw= new StreamWriter(file_name);
fileName= file_name;
writeOpened= true;
returntrue;
}
catch(FileNotFoundExceptione)
{
returnfalse;
}
}
这里才正式进入设计模式课程
首先是创建型模式Creational Pattern
创建型模式都涉及到创建对象实例的方式,因为程序不应该依赖对象如何创建和如何安排。
那么我们将创建过程抽象成一个专门的"创建器"类
工厂方法模式Factory Method Pattern
抽象工厂模式Abstract Factory Pattern
单件模式Singleton Pattern
生成器模式Builder Pattern
原型模式Prototype Pattern
简单工厂模式Simple Factory Pattern
(firstname lastname或者lastname,firstname)
public class Namer
{
protectedstring fName,lName;
publicstring GetFname()
{
returnfName;
}
publicstring GetLname()
{
returnlName;
}
}
派生类
public class FirstName:Namer
{
publicFirstName(string name)
{
inti = name.Trim().IndexOf(" ");
if(i> 0)
{
fName= name.Substring(0,i).Trim();
lName= name.Substring(i+1).Trim();
}
else
{
lName= name;
fName= "";
}
}
}
public class LastName:Namer
{
publicLastName(string name)
{
inti = name.IndexOf(",");
if(i> 0)
{
lName= name.Substring(0,i).Trim();
fName= name.Substring(i+1).Trim();
}
else
{
lName= name;
fName= "";
}
}
}
构造简单工厂
public class NameFactory
{
publicNameFactory(){}
publicNamer GetName(string name)
{
inti = name.IndexOf(",");
if(i> 0)
{
returnnew LastName(name);
}
else
{
returnnew FirstName(name);
}
}
}
使用工厂(按钮点击事件还是别的都可)
//NameFactory nameFact = new NameFactory();
Namer nm = nameFact.GetName(txtName.text);
txtFirst.Text = nm.GetFname();
txtLast.Text = nm.GetLname();