1. 问题
struct Time
{
...
public int GetHour()
{
return hour;
}
public void SetHour(int value)
{
hour = value;
}
...
private int hour, minute, second;
}
static void Main()
{
Time lunch = new Time();
lunch.SetHour(12);
Console.WriteLine(lunch.GetHour());
}
封装把一些不重要的细节隐藏起来,这样你可以集中精力处理那些重要的内容。但封装很难被掌握,一个典型的封装误用是盲目地把公有字段转为私有字段。例如在上面的例子中,程序定义了一个私有字段hour和SetHour函数和GetHour函数,而不是定义一个公有的hour字段。如果GetHour函数只是返回私有字段的值而SetHour函数只是设置私有字段的值的话,那么你除了使Time类更难使用外,你不会得到任何好处。
2. 不是解决的办法
· 如果字段是公有的,那使用起来是简单的
w 但如果你使用公有字段的话,你会失去控制权
w 要简化而不是简单
struct Time
{
...
public int Hour;
public int Minute;
public int Second;
}
static void Main()
{
Time lunch = new Time();
lunch.Hour = 30;
lunch.Minute = 12;
lunch.Second = 0;
...
}
上面的例子使用公有字段来使字段的使用比较简单。例如,你不用写:
lunch.SetHour(lunch.GetHour() + 1);
而只要写:
++lunch.Hour;
但是,这种简单的表达式是有代价的。考虑上面的例子,程序给Hour和Minute字段分别赋值为30和12。问题是30不在Hour的范围(0-23)内。但如果字段是公有的话,你就没有办法捕获这个错误。
所以虽然get和set函数比较麻烦,但它们在这方面比公有字段具有优势是很明显的。get和set函数允许程序员控制类的内在字段的读和写。这是非常有用的,例如你可以检查set函数的参数范围。
当然最理想的方法是保留公有字段提供的简单而直接的表达式和get和set函数提供的控制权。(呵呵,人总是既想偷懒又想得到很多)
3. 解决的办法
· 属性
w 自动使用get 标识符进行读
w 自动使用set 标识符进行写
struct Time
{
...
public int Hour //没有(),是H而不是h
{
get { ... }
set { ... }
}
private int hour, minute, second;
}
Time lunch = new Time();
...
lunch.Hour = 12;
...
Console.WriteLine(lunch.Hour);
C#提供了一个解决上述问题的好办法。你可以把get和set函数组合成一个简单的属性。属性的声明包括一个可选的访问修饰符(在例子中是public)、返回值(int)、属性的名字(Hour)和一个包含get和set语句的属性体。特别要注意的是属性没有括号,因为属性不是函数。属性的命名规则应符合一般的命名规则,即公有的使用PascalCase规则,而非公有的使用camelCase规则。在上面的例子中,Hour属性是公有的,所以命名为Hour而不是hour。
例子中演示了属性的用法。属性使用的语法和字段的一样,没有括号。如果你要写一个属性,那你可以这样写:
lunch.Hour = 12;
属性的set语句自动被执行。
如果你要读一个属性,你可以这样写:
int hour = lunch.Hour;
属性的get语句自动被执行。
4. get语句
l get 语句
Ø 必须返回一个有确定类型的值
Ø 功能上就像一个 “get 函数”
struct Time
{
...
public int Hour
{
get
{
return hour;
}
...
}
private int hour, minute, second;
}
Time lunch = new Time();
... Console.WriteLine(lunch.Hour);
//请注意,get和set不是关键字
当读一个属性的时候,属性的get语句自动运行。
get语句必须返回一个有确定类型的值。在上面的例子中,Time结构类有一个整型属性Hour,所以它的get语句必须返回一个整型值。
属性的返回值不能是void(从这里可以推断出字段的类型也不能是void)。这就意味着get语句必须包含一个完整的return语句(retun;这种形式是错误的)。
get语句可以在retun语句前包含任何其他的语句(比如,可以检查变量的类型),但return语句不能省略。
注意,get和set不是关键字,所以你可以在任何地方包括get/set语句中声明一个局部变量、常量的名字是get或set,但最好不要这样做。
5. set语句
· set 语句
w 是通过value 标识符来进行赋值的
w 可以包含任何语句(甚至没有语句)
struct Time
{
...
public int Hour
{
...
set {
if (value < 0 || value > 24)
throw new ArgumentException("value");
hour = value;
}
}
private int hour, minute, second;
}
Time lunch = new Time();
...
lunch.Hour = 12;
当写一个属性的时候,属性的set语句自动运行。
在上面的例子中,Time结构类有一个整型属性Hour,所以赋给这个属性的值必须是一个整型值。例如:
lunch.Hour = 12;
把一个整型值12赋给了lunch的Hour属性,这个语句会自动调用属性的set语句。set语句是通过value标识符来获得属性的赋值的。例如,如果12被赋给了Hour属性,那么vaue的值就是12。注意的是value不是一个关键字。value只是在set语句中才是一个标识符。你可以在set语句外的任何语句声明value为一变量的名字。例如:
public int Hour
{
get { int value; ... }//正确
set { int value; ... }//错误
}
6. 只读属性
l 只读属性只有get语句
Ø 任何写操作都会导致错误
Ø 就像一个只读字段
struct Time
{
...
public int Hour
{
get
{
return hour;
}
}
private int hour, minute, second;
}
Time lunch = new Time();
...
lunch.Hour = 12; //错误
...
lunch.Hour += 2;//错误
一个属性可以不必同时声明get语句和set语句。你可以只声明一个get语句。在这种情况下,属性是只读的,任何写的操作都会导致错误。例如,下面的语句就会导致一个错误:
lunch.Hour = 12;
因为Hour是只读属性。
但要注意的是,属性必须至少包括一个get或set语句,一个属性不能是空的:
public int Hour { }//错误
7. 只写属性
l 只写属性只能有set 语句
Ø 任何读操作都是错误的
struct Time
{
...
public int Hour
{
set {
if (value < 0 || value > 24)
throw new OutOfRangeException("Hour");
hour = value;
}
}
private int hour, minute, second;
}
Time lunch = new Time();
...
Console.WriteLine(lunch.Hour); //错误
...
lunch.Hour += 12;//错误
一个属性可以不必同时声明get语句和set语句。你可以只声明一个set语句。在这种情况下,属性是只写的,任何读的操作都会导致错误。例如,下面的语句就会导致一个错误:
Console.WriteLine(lunch.Hour);
因为Hour是只写属性。
而下面的例子则看上去好像是对的:
lunch.Hour += 2;
这句语句的实际运作是这样的:
lunch.Hour = lunch.Hour + 2;
它执行了读的操作,因此是错误的。因此,像+=这种复合型的赋值操作符既不能用于只读属性,也不能用于只写属性。
posted @
2008-06-17 11:16 天书 阅读(802) |
评论 (1) |
编辑 收藏
一、宏观比较(哈哈,比较高屋建瓴)
接口是为了满足外部调用而定义的一个功能约定, 因此反映的是事物的外部特性
抽象类是从一系列相关对象中抽象出来的概念, 因此反映的是事物的内部共性;
二、微观比较(还是到基层来比较好一些)
下面分别从声明,成员,实现几个角度来比较
一、关于声明:
【接口】的修饰符:new public private protected internal 如
public[public private protected internal] interface IInterface{ //interface body }
new 修饰符仅允许在类中定义的接口中使用。它指定接口有意隐藏同名的继承成员。
备注:类成员声明中可以使用与一个被继承的成员相同的名称或签名来声明一个成员。发生这种情况时,就称该派生类成员隐藏了基类成员。隐藏一个继承的成员不算是错误,但这确实会导致编译器发出警告。若要取消此警告,派生类成员的声明中可以包含一个 new 修饰符,表示派生成员是有意隐藏基成员的。
【接口】的基接口:接口可以从零个或多个接口继承, 接口不能从自身直接或间接继承,否则会发生编译时错误。接口也不能继承自类,如果可以的话那将违反了C#类不能多重继承的原则。
【接口】的接口体:很简单 用{ //接口成员是可选的 }表示
【抽象类】 关于声明,自己想想吧,除了加了个限定的abstract修饰符似乎没有太多可以描述的地方,抽象类本身也是是个类啊,除了不能被实例外。
public abstract AbstractClass{
//class body
}
【抽象类】的基类最多一个类,但却可以有n个接口
二、关于成员
【接口】的成员只能是签名,没有实现,能包括的成员是:方法,属性,索引器,事件,举例如下
Public interface IInterface
{
Void Method();//显然只是个方法说明,没有方法体。
String Name{set;get};//显然其用途是指示属性是读写、只读还是只写。
String this[int index]{get:set;} //显然其用途是指示索引器是读写、只读还是只写。
event EventHandler Even ;
}
public delegate void EventHandler(object sender, Event e) ;
接口所有的成员都不能加访问修饰符,因为既然是接口,那么所有的成员都是可以访问的。
【抽象类】的成员应该有什么,想想类吧,类有什么,它也应该什么。
特别说明的是,抽象类可以但不是必须有抽象属性和抽象方法,但是一旦有了抽象方法,就一定要把这个类声明为抽象类。
抽象方法,同接口一下,也只有方法体,没有实现。
三、关于实现
【抽象类】和【接口】都不能直接实例化
posted @
2008-06-17 10:36 天书 阅读(289) |
评论 (0) |
编辑 收藏
抽象方法(abstract )相当于接口,根本就没有实现,只等着子类来重新。
虚方法(Virtual)好歹完成了点功能。
1:abstract 方法只能在抽象类中声明,而Virtual方法都可以。
2:abstract 方法必须在派生类中重写,而Virtual方法可以重写也可以不重写
3:abstract 方法不能声明方法实体,
abstract public void SD();
虚方法则可以
public virtual void sdf()
{
Console.WriteLine("A");
}
不能将 virtual 修饰符与以下修饰符一起使用: static abstract override 。
abstract 和 virtual方法在子类中重写时必须加上关键字override
posted @
2008-06-17 09:41 天书 阅读(1075) |
评论 (1) |
编辑 收藏
不用重新Button,只通过更改Button的Region属性即可造出圆形按钮
System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddEllipse(this.btn_circle.ClientRectangle);
this.btn_circle.Region = new Region(path);
posted @
2008-06-15 13:49 天书 阅读(6008) |
评论 (3) |
编辑 收藏
某些键,如
Tab、
Return、
Esc 和
箭头键,由控件自动处理。为使这些键引发 KeyDown 事件,必须在窗体上的每个控件中重写
IsInputKey 方法。用于重写 IsInputKey 的代码需要确定是否按下了某个特殊键,并且需要返回一个 true 值。
1class MyButton :System.Windows.Forms.Button
2 {
3 protected override bool IsInputKey(System.Windows.Forms.Keys keyData)
4 {
5 if (keyData == System.Windows.Forms.Keys.Left ||
6 keyData == System.Windows.Forms.Keys.Right)
7 return true;
8 return base.IsInputKey(keyData);
9 }
10 }
重写之后就可以让Button控件KeyDown事件中箭头键响应了。
1 private void button1_KeyDown(object sender, KeyEventArgs e)
2 {
3 if(e.KeyCode == Keys.Left)
4 {
5 if (button1.Location.X >=2)
6 {
7 button1.Location = new Point(button1.Location.X - 2, button1.Location.Y) ;
8 }
9 }
10 if (e.KeyCode == Keys.Right)
11 {
12 if (button1.Location.X <= 500)
13 {
14 button1.Location = new Point(button1.Location.X + 2, button1.Location.Y);
15 }
16 }
17 }
posted @
2008-06-14 11:08 天书 阅读(4636) |
评论 (0) |
编辑 收藏
Bridge模式:关键特征
意图:将一组实现部分从另一组使用它们的对象中分离出来
问题:一个抽象类的派生类必须使用多种实现部分,但又不能引起类数量的爆炸
解决方案:为所有的实现部分定义一个接口,让抽象类的所有派生类使用这个接口
效果:实现部分与使用它的对象分离
实现:将实现部分封装在一个抽象类中
在被实现的抽象部分基类中包含一个实现部分基类的句柄
posted @
2008-06-13 20:06 天书 阅读(166) |
评论 (0) |
编辑 收藏
1:修改表格中某项
UPDATE 表格
SET "栏位1" = [值1], "栏位2" = [值2]
WHERE {条件} 2:插入语句
INSERT INTO "表格名" ("栏位1", "栏位2", ...)
VALUES ("值1", "值2", ...) 3:删除语句
DELETE FROM 表格
WHERE store_name = "Los Angeles"
4:选择语句SELECT store_name FROM Store_Information where “条件”
-=SQL语句集锦=-
--语 句-- --功 能--
--数据操作
select --从数据库表中检索数据行和列
insert --向数据库表添加新数据行
delete --从数据库表中删除数据行
update --更新数据库表中的数据
--数据定义
create table --创建一个数据库表
drop table --从数据库中删除表
alter table --修改数据库表结构
create view --创建一个视图
drop view --从数据库中删除视图
create index --为数据库表创建一个索引
drop index --从数据库中删除索引
create procedure --创建一个存储过程
drop procedure --从数据库中删除存储过程
create trigger --创建一个触发器
drop trigger --从数据库中删除触发器
create schema --向数据库添加一个新模式
drop schema --从数据库中删除一个模式
create domain --创建一个数据值域
alter domain --改变域定义
drop domain --从数据库中删除一个域
--数据控制
grant --授予用户访问权限
deny --拒绝用户访问
revoke --解除用户访问权限
--事务控制
commit --结束当前事务
rollback --中止当前事务
set transaction --定义当前事务数据访问特征
SQL函数篇:
1:
SUM GROUP BY HAVING
SELECT store_name, SUM(sales)
FROM Store_Information
GROUP BY store_name
HAVING SUM(sales) > 1500
2:
LIKESELECT *
FROM Store_Information
WHERE store_name LIKE '%AN%'
posted @
2008-06-11 20:33 天书 阅读(378) |
评论 (0) |
编辑 收藏
结论:Facade模式简化接口,而Adapter模式将接口转换成另一个现有的接口。
class Circle extends Shape{
...
private XXCircle pxc;
...
public Circle(){
pxc = new XXCircle();
}
void public display(){
pxc.displayIt();
}
}
posted @
2008-06-11 19:58 天书 阅读(125) |
评论 (0) |
编辑 收藏
1:何为设计模式?
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结可以被反复使用而且可靠性高。设计模式可以让你的程序可维护性高,可扩展性好。
2:为什么要学习设计模式?
复用解决方案——通过服用已有的设计模式,为自己的问题找到了更高的起点,避免了绕弯路。不必再为普遍,重复的问题重新设计解决方案。
建立通用的术语——交流与协作都需要一个共同的词汇基础,一个对问题共同的观点。设计模式在项目的分析和设计阶段提供了一个通用的参考点。
更高层次的视角——这样的视角将你从“过早处理细节”的“暴政”中解放出来。
模式本身就是对如何创建优良面向对象设计策略的实现:
1.针对接口编程
2.优先使用对象组合,而不是类继承
3.发现并封装变化点
abstract factory、adapter、strategy体现了针对接口编程,
composite、bridge体现了优先使用组合而不是继承等。
深入到具体模式的讨论,记录一些需要注意的问题:
1.Adapter与Facade模式的区别
它们都是包装器,但是两者也有细微的区别:
.两个模式中,我们都有已经存在的类(或者说系统)
.Facade模式中,我们无需针对接口编程;而Adapter模式我们必须针对接口编程
.Adapter模式通常是为了保持多态,而Facade模式对此不感兴趣
.动机不同,Facade模式是为了简化接口,而Adapter模式是针对一个现存的接口编程
结论:Facade模式简化接口,而Adapter模式将接口转换成另一个现有的接口
2.Bridge模式的理解
Bridge模式的意图是将抽象部分与它的实现部分分离,使它们可以独立的变化。这里的关键点是需要理解“实现部分”,如果把“实现部分”看成“对象外部、被对象使用的某种东西”,此模式就很好理解了。我们将变化转移到一个使用或者拥有变化的对象(此对象是指抽象类的对象和用来实现抽象类的派生类的对象)。当出现继承的类爆炸情况时,也许你该考虑此模式的应用场景了。
3.Strategy模式是一种定义算法家族的方法,所有的算法都做相同的工作,它们只是拥有不同的实现。当你的代码中出现了很多switch或者if else的语句,你应该考虑此模式。Strategy模式带来的缺点是类的数量的增加,在java中可以通过将实现类作为嵌套类放在Strategy抽象类中来解决。
4.singleton模式:
保证一个类有且仅有一个实例,并提供一个访问它的全局访问点
单线程应用:
第一种:静态初始化
public class Singleton {
private Singleton() {
}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
posted @
2008-06-11 19:46 天书 阅读(164) |
评论 (0) |
编辑 收藏
1Public Function IsBlank(ByRef TempVar)
2 'by default, assume it's not blank
3 IsBlank = False
4 'now check by variable type
5 Select Case VarType(TempVar)
6 'Empty & Null
7 Case 0, 1
8 IsBlank = True
9 'String
10 Case 8
11 If Len(TempVar) = 0 Then
12 IsBlank = True
13 End If
14 'Object
15 Case 9
16 tmpType = TypeName(TempVar)
17 If (tmpType = "Nothing") Or (tmpType = "Empty") Then
18 IsBlank = True
19 End If
20 'Array
21 Case 8192, 8204, 8209
22 'does it have at least one element?
23 If UBound(TempVar) = -1 Then
24 IsBlank = True
25 End If
26 End Select
判空函数应用
1<%
2'关键字从Title里面选
3classid = request("classid")
4key = request("keyword")
5if IsBlank(classid) and IsBlank(key) then
6 sql = "select Resource.ID, Title, ClassID, CName from Resource, Class where Resource.ClassID = Class.ID "
7else
8 sql = "select Resource.ID, Title, ClassID, CName from Resource, Class where Resource.ClassID = Class.ID "
9 if CINT(classid) = -1 then
10 sql = sql
11
12 else
13 sql = sql + " and ClassID = " & classid
14
15 end if
16
17 if len(key) > 0 Then
18 sql = sql & " and Title like '%"& key &"%' "
19
20 else
21 sql= sql
22
23 end if
24end if
25
26set rs = server.createobject("adodb.recordset")
27%>
posted @
2008-06-08 21:58 天书 阅读(357) |
评论 (0) |
编辑 收藏