cnblogs.com

July 2007 - Posts

管理概述
     摘要: 先谈谈管理的概述,然后再详细分解。  阅读全文

风焰庄主 2007-08-01 13:08 发表评论
Asp.net中动态在中加入Scrpit标签
许久以前,写过一篇《asp.net页中动态加入样式表文件》,后来发现在使用时如果每页都写这么个函数真是很麻烦,于是自己写了一个Page的派生。将这个函数加了进去。
      /**//// <summary>
    
/// 作者 邹健
    
/// 日期 20070202
    
/// 重载的Page类。
    
/// </summary>
    public class ChPage : Page {
        
/**//// <summary>
        
/// 构造函数。
        
/// </summary>
        public ChPage() { }
        
/**//// <summary>
        
/// Render函数。
        
/// </summary>
        
/// <param name="writer">HtmlTextWriter。</param>
        protected override void Render(HtmlTextWriter writer) {
            
if (writer is System.Web.UI.Html32TextWriter) {
                writer 
= new FormFixerHtml32TextWriter(writer.InnerWriter);
            }
            
else {
                writer 
= new FormFixerHtmlTextWriter(writer.InnerWriter);
            }
            
base.Render(writer);
        }
        
/**//// <summary>
        
/// 设置Html标签内,的Link标签,如Css
        
/// </summary>
        
/// <param name="cssfile">Css文件。</param>
        protected void SetHtmlLink(string cssfile) {
            HtmlLink myHtmlLink 
= new HtmlLink();
            myHtmlLink.Href 
= cssfile;
            myHtmlLink.Attributes.Add(
"rel""stylesheet");
            myHtmlLink.Attributes.Add(
"type""text/css");
            Page.Header.Controls.Add(myHtmlLink);
        }
        
/**//// <summary>
        
/// 该函数可获得web.config中的字符串。
        
/// </summary>
        
/// <param name="Str">指定项的键值。</param>
        
/// <returns>返回键值所指的值。</returns>
        protected string GetString(string Str) {
            
return System.Configuration.ConfigurationManager.AppSettings[Str];
        }
    }

但是后来发现在使用asp.net编程时,如果应用模板页的话,不止是css文件不容易后往里添,javascript文件也是如此,虽然说在模板页的<head />中建一个contentplaceholder也算可以,但那种方法毕竟不太雅,有失风范。于是就想按这种添加<link />标签的方法来泡制<script />
但发现在System.Web.UI.HtmlControls中有HtmlLink来表现<link />但却没有表现<Script />标签的类。
没办法了,因为懒所以只能自己写一个了,代码不长,如下。
namespace Chsword.Class {
    
/// <summary>
    
/// 可以生成script标签
    
/// </summary>
    [ControlBuilder(typeof(HtmlEmptyTagControlBuilder)), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    
public class HtmlScript : HtmlControl {
        
// Methods
        public HtmlScript()
            : 
base("script") {
        }
        
protected override void Render(HtmlTextWriter writer) {
            writer.WriteBeginTag(
this.TagName);
            
this.RenderAttributes(writer);
            writer.WriteEndTag(TagName);
        }
        
protected override void RenderAttributes(HtmlTextWriter writer) {
            
if (!string.IsNullOrEmpty(this.Src)) {
                
base.Attributes["src"= base.ResolveClientUrl(this.Src);
            }
            
base.Attributes["type"= "text/javascript";
            
base.RenderAttributes(writer);
        }
        
/// <summary>
        
/// 脚本的URL
        
/// </summary>
        [UrlProperty]
        [DefaultValue(
"")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        
public virtual string Src {
            
get {
                
string text = base.Attributes["src"];
                
if (text == null) {
                    
return string.Empty;
                }
                
return text;
            }
            
set {
                
base.Attributes["src"= MapStringAttributeToString(value);
            }
        }
        
string MapStringAttributeToString(string s) {
            
if ((s != null&& (s.Length == 0)) {
                
return null;
            }
            
return s;
        }
    }
}
随后我又在原来重 写的ChPage类中添加了一个函数
        /// <summary>
        
/// 设置script现在只能是type=text/javsscript的
        
/// </summary>
        
/// <param name="src">脚本地址</param>
        protected void SetHtmlScript(string src) {
            HtmlScript myHtmlScript 
= new HtmlScript();
            myHtmlScript.Src 
= src;
            Page.Header.Controls.Add(myHtmlScript);
        }

使用方法

原来的页面脚本是这样的
vb.net
Partial Class Default
    
Inherits Page
C#应该类似Default : Page
现在只要改成
Partial Class Default
    
Inherits ChPage
C#相应为 Default:ChPage
就可以了

使用时只要在载入前的某个事件,比如Init或Load写 SetHtmlScript("/Javascript/MicrosoftAjax.js")
这样就OK了
 
直接再看看生成的HTML,吼吼,已经有你添加的<script src=""/Javascript/MicrosoftAjax.js" type="text/javascript"></script>了

本如果文章中有不足的地方请大家要提出啊
文章来自chsword[邹健的博客]允许转载麻烦留言




邹健 2007-08-01 12:47 发表评论
颠覆传统-面向对象的设计思想(序章续)
    自从《颠覆传统-面向对象的设计思想(序章)》发布出来后看的朋友和评论的朋友很多,有说好的,也有说不好。当然也有很多朋友在文章的评论中发表了自己的见解,在这里我就一些比较典型的评论做一下解释。
  • 来自名为wanghualiang 的评论


Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

-->很佩服楼主的发散型思维。但是远远还没到颠覆传统的地步。
这里谈谈我的观点,
面向对象设计时完全从接口来描述对象本身的特性是不是有问题。
从鱼是不是可吃应该只能作为其一个属性来辨识,
Class Fish
{
public bool IsEatable;
}
当客户想吃这条鱼的时候,IsEatable
=true;如果是河豚的话就是 False了。
当然有许多种不确定的因素,在可吃不可吃之间。那我们应该
[Flags]
Enum Eattype
{

DeliciousEate,
//美味
Distasteful,
Barbed,
..
}

Class Fish
{
public Eattype eattype;
    我想wanghualiang 的评论代表了相当一部分朋友的看法,从传统的面向对象思想(或者说普遍接受)的观点来看这样做是没有问题的,甚至还被作为了Demo写入了很多的面向对象的教科书。但是实际上这种看法是存在问题的,至少我个人是这么认为的,首先我们需要考虑的问题是:鱼自己能不能决定自己能不能吃,能不能决定自己好不好吃?应该是不能吧,决定鱼能不能吃,好不好吃的应该是吃鱼的对象对吧。也许从普通人的角度来看河豚是不能吃的,但是从高明的大厨或者资深的老饕的角度来看河豚就是无比的美味了,这也是我在序章的最后专门添加一幅图片重点解说对象行为的原因。
    话说回来,既然鱼不能决定能不能吃、好不好吃,也就是说明能不能吃的行为不是有鱼能够决定的,那么也许有人会问那为什么要实现IEatable接口呢,和直接做一个属性不是一样吗?这个问题问的非常的好,确实既然鱼不能够决定自己能不能吃、好不好吃,那么为什么鱼要实现IEatable接口呢。其实,在Fish上实现IEatable接口完全是出于使用方便性和接口的层次(后续的文章中会重点讨论这个问题)来考虑的,完全面向对象的搞法应该是有另外一个对象来鉴定这个鱼是否能吃、好不好吃的(这也是基于设计的平衡来考虑的,可以参看开放-封闭原则)。在这个地方使用接口和属性本质上没有什么差别,但是一旦鉴别鱼能不能吃、好不好吃的鉴别方式(实现方法)发生变化的时候,使用属性的方式就难以扩展了,只能修改代码了,但是使用接口的好处是我可以使用其它的方式补救,例如做一个实现IEatable接口的装饰对象来装饰鱼对象。
    另外,导致需要鱼对象实现IEatable接口的原因可能是出于接口隔离原则的考虑,如果使用属性来辨别鱼是否能吃,必然使用的地方就依赖鱼对象了,提高了系统的耦合性。示意代码如下:


Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 '检索是否可以吃的食物
 2 Public Function GetEatableFish(ByVal foods As IEatable()) As IEatable()
 3 
 4     '用于保存列表
 5     Dim tempList As New ArrayList
 6 
 7     '循环的检索
 8     For Each item As IEatable In foods
 9 
10         '判断是否可以吃
11         If item.IsEatable Then
12 
13             tempList.Add(item)
14         End If
15     Next
16 
17     '返回结果
18     Return tempList.ToArray(GetType(IEatable))
19 
20 End Function
21 
22 '是否可以吃接口
23 Public Interface IEatable
24 
25     '是否可以吃
26     Function IsEatable() As Boolean
27 
28 End Interface
   软件设计的时候没有一味的好,也没有一味的差,任何事情都有其两面性,这个是需要取舍的,我们能够做到的事情就是让设计可控,如果设计失控了,那就全部完蛋了。话说回来,如果能够确认当前的系统中评判鱼能不能吃的标准不会发生改变,把这个不会发生改变的东西集成到鱼对象中是完全可以的,在具体的实现上用属性来实现也是一个非常不错的搞法。
  • 来自名为 Anders Liu 的评论


Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

-->嗯。。。建议你在多想想再继续写。

比如这个:
public class Goby : IFish, IClimbable, IEatable
我认为这样比较好:
public class Goby : Fish, IClimbable, IEatable

看到区别了么? 
    至于Anders Liu 的评论应该与wanghualiang 的意见基本上是一致的,如果我没有理解错误的话。我们引入一个Class的时候需要考虑的是引入这个Class的目的,如果没有任何目的的引入一个类或者是仅仅简单的为了封装一个方法来引入一个类是不可靠的,后面我会写一篇随笔来专门讨论类和接口。




我是程序员 2007-08-01 11:57 发表评论
ActiveX在.NET 2005中的实现(一)
http://homer.cnblogs.com/archive/2005/01/04/86473.aspx中看到了一篇关于如何名叫“用C#编写ActiveX控件”的文章,受益匪浅。
但该文章可能是在旧版本的.NET开发环境中实现的,在.NET 2005怎么实现也没能成功实现,于是自己从头开始做了一个开发,几经周折终于实现,现在分享给大家。
第一步:ActiveX在.NET中的实现
 

如上图所示在.NET中使用UserControl来实现ActiveX。代码如下。
 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Drawing;
 5 using System.Data;
 6 using System.Text;
 7 using System.Windows.Forms;
 8 using System.Runtime.InteropServices;
 9 
10 // Add in these    using clauses for this example
11 using System.Reflection;
12 using Microsoft.Win32;
13 
14 
15 namespace ActiveXDotNet
16 {
17      //[ClassInterface(ClassInterfaceType.AutoDual)]
18     public partial class myControl : UserControl, AxMyControl
19     {
20         public myControl()
21         {
22             InitializeComponent();
23         }
24 
25         private String mStr_UserText;
26 
27         public String UserText
28         {          
29             get { return mStr_UserText + " OK"; }
30             set {
31                 mStr_UserText = value;
32                 this.txtUserText.Text = value;
33             }
34         }
35 
36         private void button1_Click(object sender, EventArgs e)
37         {
38             this.txtUserText.Text = "Hello World";
39         }
40 
41         private void button2_Click(object sender, EventArgs e)
42         {
43             InputForm frmInput = new InputForm();
44             frmInput.ShowDialog();
45         }
46 
47     }
48 }
49 

其中,将在HTML中使用的方法在接口AxMyControl中实现,代码如下:
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 
 5 namespace ActiveXDotNet
 6 {
 7     interface AxMyControl
 8     {
 9         String UserText { set; get; }
10     }
11 }
12 

Assembly.cs中的特殊设置:
1 // Setting ComVisible to false makes the types in this assembly not visible 
2 // to COM components.  If you need to access a type in this assembly from 
3 // COM, set the ComVisible attribute to true on that type.
4 [assembly: ComVisible(true)]

这样,一个简单的基于.NET的AticveX控件就开发完成了,下一次讲解具体的调用方法。


Guangyu.Ren 2007-08-01 11:49 发表评论
ObjectBuilder应用之TypeMappingPolicy、SingletonPolicy
     摘要: ObjectBuilder中提供了很多Policy,甚至还可以按自己的需要任意扩展,那对于已经提供的Policy,我们应该如何正确的使用呢?这篇文章我会先介绍一下其中的SingletonPolicy。
在我们实际的项目开发中,经常会遇到多次创建同一个类的情况,如果按照一般的方法去new一个类,那么每new一次,就会产生一个实例,对于小型系统完全没有问题,但当系统比较庞大时,就应该认真思考了。
  阅读全文

FrankFei 2007-08-01 11:45 发表评论
赢在用户—UCDChina范晓燕译作上市!

UCD(User Centered Design)所提倡的“以用户为中心来进行设计”,要求产品设计人员从内心把用户的需求置于一切需求之上。我们相信,当网站(或其他任何产品)的设计切实考虑到真实用户(他们的需求、他们的观点,甚至他们令人抓狂的怪癖)时,产品就会更加成功。但是有时我们周围的人不会像我们一样清楚地看到这个真相。

这时候我们需要一个工具来帮助我们的合作伙伴了解并记住“用户的需求”,人物角色(Personas)就这样应运而生了。

人物角色作为UCD方法中最重要的一个工具,它使用的所有的手段,无一不是为了促进和巩固UCD思路。《User is Always Right》(中文译名《鸁在用户》)详细地描述了角色创建和应用的完整过程。在此之前,国内的产品设计界、UCD的拥趸者都只能根据一些零星描述和个人理解在这条路上艰难地摸索。

作为这个行业的一员,我对两位作者(Steve Mulder、Ziv Yaar)充满了深深的敬意和感谢,正是他们的分享,使我更加坚信自己选择了一个正确的方向,在这条路上走得也更坚定、更有信心。

很荣幸自己能有机会为这个行业和我的同行们贡献一点绵薄之力,同时,正如作者所说:“人物角色是一个发展中的工具。”这意味着,我们,中国设计师,也有机会在它的发展过程中贡献出自己的智慧。这是机遇,也是挑战。

本书在China-pub可以预订了:
User is Always Right



childchen 2007-08-01 10:53 发表评论
突然发现一篇很受用的帖子~面向行为
http://www.cnblogs.com/zengezenge/archive/2007/07/31/837860.html
引用:我们一直以来都从“Is A”的角度来对对象进行归类,但是仔细的想一想,“Is A”的标准是什么?我们怎么样才能判定一个对象“Is A”另外一个对象呢?大家是不是基本靠猜测或者凭经验在做?这也是软件设计一直被当作是一种艺术行为的原因。

        是啊,这个IS A到底是指的什么,我们为什么没有想到ACT FROM A。
        从开始接触面向对象到现在,真正用到它的地方并不多,而只是把它当做一个理念在推广,朋友曾经说过一句话:你这样太累了吧,全部面向对象设计不现实。其实不是不现实,而是我们没有充分理解这种理念,而导致现在很累。

        抽象出来一个类,抽象出来一个方法,实现一个接口并不能说明就在使用面向对象,如果这种实现让本来很简单就可以完成的工作变得异常复杂,还是不用的好。一个好的设计是从一个基类开始的,就像.NET,OBJECT是一个多么好的抽象。
        我长期从事财务系统的开发,其它从这里面也能看出很多可以抽象的单位,比如:报表这个单位就可以做为一个总的基类,他可以抽象出取数,布局,打印,预览,导出接口四个部分,在不同的模块里可以有不同的实现,而现在我经历的系统中都没有这些,具体业务具体实现。
        我只是举一个例子,也许里面有说的不对的地方请大家指教。
        其实在我接触到的这些模块里面,有一个给我感触很深,那就是凭证模块,其实这个模块最可以用面向对象的理念去实现了,可以抽象的东西很多,接口也很多,其中方法属性又是异常的复杂,如果可以合理的设计真的可以达到事倍功半的效果,有这方面经验的朋友一起讨论一下吧~

土星的狗狗 2007-08-01 10:04 发表评论
发现移动太NB了,验证码图像路径直接包含验证码
    今天去移动上查看手机通话记录,习惯性的看了一下验证码,发现比上次好了一点,用我以前的文章,不好识别了.
    但查看了一下图片路径,一下子就晕了.图片的路径竟然是:   
http://www.he.chinamobile.com/Service/MakeNewAttest?randCode=4955
  

    发现移动太是太牛了. 佩服佩服
   

阿牛 2007-08-01 09:05 发表评论
linq to sql中的metadata

下面是简单的描述

MetaModel
       |
   MetaTable/ MetaFunction
             |
          MetaType
               |
          MetaDataMember      

位于最顶部的是MetaModel,它由DataContext的Mapping属性提供,MetaModel 中有多个MetaTable /MetaFunction,每个MetaTable中有一个RowType属性(即MetaType),MetaType由多个MetaDataMember组成.


在dbml或是linq to sql生成的代码中对应的东西,你都可以在这些metadata中找到, 因此,这部分数据可以作为应用程序框架的metadata. metadata是应用程序框架中最重要一环.我在使用中唯一感到不方便的是它没有明确的提供字符串类型的size,MetaDataMember的DbType属性总是类似这样的 (varchar(10)),你需要自己解析它,或者自行定义添加一个Size Attribute),由于代码生成的关系,这有点不方便. 同样,MetaTable.TableName也会表现出ower,如dbo.Quotation.

有点不太一致的地方是你在强类型的DataContext类中所看到的InsertXXX,UpdateXXX,DeleteXXX方法,其实都对应在每个具体的MetaTable中, 并没有如你所想的提供在MetaModel类中 ,MetaTable这个类提供了InsertMethod,UpdateMethod,DeleteMethod等MethodInfo类型的属性,同样,每个具体类的OnValidate,OnLoaded在MetaTable表也有对应的表示OnValidateMethod,OnLoadedMethod.

在具体的实现上,MetaTable 有两个具体的实现,AttributedMetaTable ,MappedTable  ,这两个是内部的类型,当使用attributed 声明映射时将会使用AttributedMetaTable类型,而使用map 文件时,将会使用MappedTable . 有人有使用Attributed映射好还是xml文件映射好的疑问,其实当这些attributed还是xml转换为metadata表示后,其它的操作都是一样的,理论上linq to sql是不管是你使用那种方法映射的,因此,不存在两者性能谁好谁坏的问题.

上面所说的也同样反映在MetaFunction之上,同样的,它也有针对attributed和mapped的实现(AttributedMetaFunction,MappedMetaFunction)

btw : 在用reflector查看linq to sql 实现时,会发现一种非常常见的模式,就是先声明一个abstract class ,然后在内部声明一个或多个抽象类实现,这些实现都是不公开的.  这种设计方式通常用在不想过早实现接口,但又想做实现隐藏和分离的场合. 当然在.net 中,abstract class代替接口使用的场景还是比较多的,特别是在早期,由于com接口的负面影响,一些宣传中甚至有鼓励类代替接口的现象,这都是不恰当的.


下面这行代码表示只获取能保存并排除关系的所有成员
MetaType metaType=db.Mapping.GetTable(typeof(Quotation)).RowType;
   var list=(from m in metaType.DataMembers where m.IsPersistent==true && m.IsAssociation==false  select m).ToList();

下面这段测试代码演示如何使用xxxAccessor 来代替Reflect
  MetaTable t = db.Mapping.GetTable(typeof(Quotation));
        Quotation q=db.Quotation.FirstOrDefault();

        MetaDataMember member=t.RowType.DataMembers.First(item => item.Name == "Id");
        Assert.AreEqual(member.MemberAccessor.GetBoxedValue(q), q.Id);

        string id = "test";
       object obj = q;
        member.MemberAccessor.SetBoxedValue(ref obj, id);
        Assert.AreEqual(q.Id, id);

        string id2 = "test2";
        member.StorageAccessor.SetBoxedValue(ref obj, id2);
        Assert.AreEqual(q.Id, id2);

上面这段测试的思想可以比较方便的为entity类提供一个this属性,让使用者通过字符串来取值或设置值.

综合所述, 除了作为应用程序metadata的提供者外,linq to sql 的metadata还可以用来有效的避免reflection,不知道大家还有其他用法没有.

 



jjx 2007-08-01 07:24 发表评论
颠覆传统-面向对象的设计思想(序章)
    从我们最初接触面向对象思想的时候,我想我们接触到的第一个概念应该就是“”,我们一直在讨论诸如如何设计类、如何实现类等高深的问题,但是我们有没有思索过到底什么叫做“类”,类的本质是什么?。按照大多数的面向对象的书籍中的介绍来看,类就是一个数据结构,封装了数据和操作,对于这样的答案,我估计大家都不会满意。
    那到底什么是类呢?在讨论这个问题之前,我们先探讨一下类的由来。“”在英语对应的单词是“Class”,如果大家翻一翻英语词典就可以查到“Class”的原意是指“种类、把...分类(或分等级)”。Class的概念最早应该是从分类学来的,意思是把对象进行归类(说的可能有些不太准确,欢迎那位高人指正),例如生物学上会根据某一个标准将生物分为动物和植物两大类,然后再根据其它的一些标准将动物又分为鱼类、爬行动物类、两栖动物类等不同的种类,如下图所示:

    说到这里,可能大家会欢呼:原来面向对象的类就是分类,太好了!我最擅长这个了!别高兴的太早,谁知道面向对象的分类标准是什么吗?是生物学的标准,还是能不能爬树的标准?不同的标准,导致分类的结果完全不同,如下图所示:

    假设现在需要要写一个弹涂鱼的类(又名虾虎鱼,英文名为Goby,一种可以爬上陆地并且会上树的鱼类,据说味道极其鲜美,有海上人参之说) ,怎么写?是不是太容易了,看下面的代码,分分钟就搞定了:


Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 '
 2 Public Class Fish
 3 
 4 End Class
 5 
 6 '可爬树的鱼
 7 Public Class ClimbableFish
 8     Inherits Fish
 9 
10 End Class
11 
12 '弹涂鱼
13 Public Class Goby
14     Inherits ClimbableFish
15 
16 End Class
    打完收功,貌似很完美的解决问题,但是这个时候又添加了一个分类标准,能吃的鱼和不能吃的鱼(鲨鱼能吃,俺吃过,味道不咋地,在这里假设鲨鱼不能吃),又该怎么办,Stupid,再写一个“EatableFish”类不就得了,让可爱的弹涂鱼从可以吃的鱼派生,我最喜欢能吃的鱼了!且慢!动手之前我想搞清楚一个问题:EatableFish从那个类派生?从ClimbableFish类派生?难道可以吃的鱼都是会爬树的鱼?从Fish派生,那么是不是说会爬树的鱼都不能吃?这个时候是不是该咒骂微软为什么不在.NET中支持多重继承?算了,还是转投Java阵营算了。旁边的一位兄弟弱弱的来了一句:好像Java也不支持多重继承吧。怎么办?难道我们就没有办法解决这个问题了吗?
    貌似用分类学的搞法搞不定面向对象的类耶,我们错了吗?但是很多教科书上面就是这么说的类的继承是“Is A”(是一个)的关系呀,弹涂鱼是“Is A”能吃的鱼、弹涂鱼“Is A”能爬树的鱼,念起来蛮通顺的嘛。错了!我们都被教科书给误导了!面向对象关注什么?关注的是对象的行为,面向对象是使用行为来对对象进行分类的!在面向对象中派生类为什么能够替换基类(替换原则),不是因为派生类是一个基类,而是因为派生类具有与基类一致的行为,在派生类与基类的行为不一致的情况下派生类仍然是一个基类(如果有人敢否认这个,大家说怎么办?旁边有人喊道:砍死他!),但是这个时候派生类消减了基类的行为,违背了替换原则,这也是恶心设计的由来。所以说,对于面向对象而言我们要关注“Act As”,用“Act As”的标准来对对象进行归类,至于什么“Is A”之类的伪标准统统扔到它姥姥家去。
    旁边有人不干了:你跟我说说属性是什么动作!对呀,属性是个什么动作呢?那么请有如此疑问的朋友仔细的考虑一下,是不是可以将属性考虑为GetXXX和SetXXX的两个方法,至于说字段怎么怎么地的某些兄弟俺就不多说了,回去自个好好想想吧,有些东西是属于开发平台为我们做了很多的工作,只不过我们不知道而已。
   好,问题到这里已经有些眉目了,我们该讨论如何使用“Act As”来对对象进行分类了。
   高手出招了,代码如下:


Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 //可爱的小鱼接口
 2 public interface IFish
 3 {
 4 }
 5 
 6 //可爱的爬树接口
 7 public interface IClimbable
 8 {
 9 }
10 
11 //可以吃接口
12 public interface IEatable
13 {
14 }
15 
16 //弹涂鱼出场了
17 //我要扮演鱼
18 //我要扮演爬树高手
19 //我要扮演可以吃的美味,貌似没有人愿意扮演这个
20 public class Goby : IFish, IClimbable, IEatable
21 {
22 }
    高手!请问我需要怎样才能表演才能扮演成一条鱼呢?高手愕然。
    看来我们的高手还是没有摆脱“Is A”的荼毒呀!我们不要鱼!我们要的是行为!行为由什么决定的呢?由要用你这个类的地方期望要的行为来决定的,例如我需要一个能够提供游泳行为的对象,你就可以抽象"ISwimable"这个动作(这个单词可能不对),然后寻求实现这个动作的对象就可以了(接口倒置原则)。
    有些朋友可能会有一些疑问,既然是动作,那么动作之间怎么会有继承呢(接口的继承)?例如:


Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

-->1 //我是一个数据提供源
2 public interface IDataSource : IDisposable
3 {
4 }
5 
    仔细想想,这个是继承吗?是“Is A”吗?不是!不知道大家玩过拳皇或者其它的格斗游戏没有,要知道分别连续按键是可以组合出一个大招的,在某些情况下,对象的使用者或者理论一点的说法消费者,需要是对象同时提供上述的两种行为,不过分吧。软件设计的时候往往就是这个地方出问题,如果没有分清楚的话,很有可能把本应该拆分的动作当作一套组合拳给打了,这也是混乱的开始,重构的原因。
    好了,今天就写到这里吧,以后有时间我会再详细的讨论如何分拆动作,如何设计类的话题。




我是程序员 2007-07-31 23:40 发表评论
理想的 ASP.NET AJAX (Part 2 - Server Centric)

使用ASP.NET的话……

ASP.NET的最大优势就是组件化,在UI上更明确地说就是控件化,但这却为AJAX带来了不少问题。

首要问题是输出HTML不由我们控制。复杂的GridView不说,我们就来看简单的CheckBox,在你不对它设置任何样式属性和文本时,它是一个单纯的<input />,加上文本的话文本会被放在<label />中以便点击文本与点击<input />等效,如果再加上样式属性的话外围就再多一个<span />用于设置样式。如果你获得了一个CheckBox的ClientID,那么通过$get()(指document.getElementById操作)获取到的是<span />还是<input />呢?答案是那个<input />。

这时候真正的问题就出现了,假如我有一组CheckBox放在一个大的<span />容器里面,当我在客户端选中一个CheckBox的时候它就从这个容器里把自己删除掉(然后转移到另一个<div />容器中)。我们关注的只是这个<span />容器内发生的事情,当我们通过$get()获取到CheckBox对应的<input />后如何知道它的parentNode的<span />是属于CheckBox的呢还是作为容器的呢?这个问题可以通过对作为容器的<span />添加id解决掉,然而我们仍需要手动判断<input />的parentNode是不是CheckBox的一部分以便知道是否要将它也一起删除掉。当然,你会说我的CheckBox不设置任何样式属性,不存在此问题。然而你能够确保这个CheckBox永远不会被设置样式属行吗?甚至可能是通过Skin而被“意外”的设置了样式属性。总而言之,一个CheckBox是否有<span />以及是否有<label />都是不确定的,而且是不正交的设计选项——有很多不同的因素可能导致它们出现。

这类问题在我们仅仅针对ASP.NET服务器端编程时可以完全不管,而且还很爽的样子——看看,我们可以全然不知道客户端发生什么事的前提下,甚至连输出什么样的HTML也不用管,也照样能设计交互式的Web。然而当我们需要考虑客户端交互的时候,这就很不爽了,ASP.NET控件这种完全隐藏客户端细节的做法让我们难以对输出的HTML进行DOM编程。

通过ASP.NET AJAX解决?

在Atlas出来的时候,我确实希望过能够在一定程度上解决上述问题,最多我就由server centric改到client centric好了,并且我也一直尝试着用Atlas进行client centric的实验性项目,然而得出的结果一直都不怎么好。

我们继续以CheckBox为例吧,不过这次改变对象为客户端的CheckBox,也就是由<input />初始化而来的Sys.UI.CheckBox。Atlas在设计的初期为这些控件考虑了很多,虽然当时控件仅有简单的几个,这里面最强大的设计思想应该就是绑定(bind)了,允许用户自行定义绑定的实现方式,而不仅仅是如同ASP.NET服务器端那样仅仅支持简单的双向绑定及自定义的单向绑定。

然而很快Atlas进入了Beta阶段,为了1.0的及时发布中心转移到了UpdatePanel等的服务器端控件上,客户端控件再也得不到重视,功能不再更新,甚至为了兼容服务器端控件的更新而被迫放弃部分原有的客户端功能。这时候使用ASP.NET AJAX进行client centric开发就变得越来越不可能了。

另外,使用ASP.NET AJAX进行client centric开发还面临一个不够search engine friendly的问题,因为数据都是输出到客户端再展示的,因此HTML本身并不包含多少有语义的内容。我曾经尝试做一个类似WebPart效果的门户页,完全不使用WebPart而使用Atlas自带的拖放支持实现是没问题,虽然其自带的拖放并不完美而必须手工添加不少东西,然而我真正面临的问题是页面第一次输出应该输出什么。

方案1是真正的client centric,好像GMail那样,一出来是空白页,显示loading,这时候通过XHR去和服务器沟通然后再添加内容到页面上,这显然是完全不照顾搜索引擎的做法,对于GMail这样本来就不应该被索引的页面当然没问题,但是大众网站这样做就不好了。

方案2是服务器端先根据用户的Profile生成用户最后一次拖放保存的页面,之后的拖放及保存工作才由客户端负责处理。然而这意味着同一套逻辑我需要实现两次,可拖放的部件在服务器端要是一个Control,在客户端同样要是一个Sys.UI.Control,同事都具备串行化为Profile已经从Profile并行化还原的能力,这样工作量就大大增加了。

之后,从ASP.NET Control Toolkit我们可以看到,客户端Control的地位已经逐步被Extender取代了,因为Extender可以被看作是一组由Behavior、Web Service等元素组成的部件,它不再关心DOM元素在客户端作为一个Control的完整性和独立性,而仅仅是考虑这些DOM元素应该表现出来的行为从而将这些行为附加到DOM元素上面去。这样思想让我们面对上面二选一的情况时有了更好的选择——在服务器端应该注重Control的整体,而在客户端则仅关注Control输出的DOM元素应该具备的Behavior。因此,在上例中我不再需要管一个可拖放部件如何作为一个客户端Control存在,我仅需要知道这个部件是一个<div />元素并且它具有可拖放的Behavior就够了,而无论何时代表整个部件包括其内容的只有服务器端Control。

这样看来,如今的ASP.NET AJAX已经有相当的价值,前提是你有能力针对你的应用开发相应的Control和Behavior。至于未来的ASP.NET AJAX能够为开发者再提供多少便利,这已经很难说了,因为继续在ASP.NET AJAX上面增加client centric的支持,倒不如把精力投入到Silverlight的研发上面去,ASP.NET AJAX很可能不会再有重大更新版本,能把ASP.NET Futures中有价值的AJAX功能都RTM就已经算好了。

最后,如果大家觉得这个系列的文章好的话,欢迎订阅Cat in Chinese(feed)或Cat in dotNET(feed)。将来话题可能将转移到Silverlight,一个我认为比ASP.NET AJAX更具潜力的框架上。



Cat Chen 2007-07-31 23:32 发表评论
区域性和变量名:编码的中文世界
     摘要: 写本文倒不是说明本文所谓的可行是值得推荐的,而是说它是对的。倒是希望您能够顺带学习一下MSDN中ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.chs/dv_fxdesignguide/html/87a4b0da-ed64-43b1-ac43-968576c444ce.htm链接中所提到的一些变量命名的规则。其实我一直不相信本文的内容是对的,但是...  阅读全文

volnet(可以叫我大V) 2007-07-31 22:16 发表评论
设计模式在JavaScript中的应用(2) -- Observer
作者:Truly
日期:2007.7.31

上次我们讨论了Web开发中最重要的设计模式MVC,今天我们要讨论的是Observer模式,与MVC这样的大型设计模式相比,Observer模式则要轻量很多。废话不多说了,进入主题

Obsever简单应用

请先看一段代码:

// the process array calling after page loaded for page listener.
var PageLoadListener = new Array(); 

// page listener
function onDocumentLoaded()
{
    
for (var a in PageLoadListener)
    {
        
if(typeof  PageLoadListenerAngel  == 'function')
            PageLoadListenerAngel();
    }
}
// Add a listener to current page to run all function on the page.
if (document.addEventListener)
 document.addEventListener('DOMContentLoaded', onDocumentLoaded, 
false);
else  
 window.attachEvent('onload', onDocumentLoaded); 

而在另外一个js中我们定义:

PageLoadListener.push(domLoaded);    // push the domLoaded function into the listener array.

// a method need to call after page is loaded
function domLoaded()
{
    alert('document loaded');
}

通常我们经常要处理window.onload事件,例如使用下面代码来指定onload事件
window.onload=aFunction

    而当我们这样的方式声明的时候,很可能会覆盖已经定义过的window.onload事件,或者我们这里还有很多事件要在onload执行,那么如何应对这种情况呢?Observer模式恰好可以用来处理这种情况。首先我们需要为页面定义了一个监听器,检测页面中需要处理的事件,然后定义一个全局的监听器数组。这样需要处理的事件都可以注册到这个监听器数组中,然后统一进行调用。
   
    如上面代码中的,我们将需要处理的事件名通过下面代码

PageLoadListener.push(domLoaded); 

    注册到Listener数组中,这样的注册过程可能遍布到不同的js文件或脚本块中,最后使用监听器集中对数组中的元素进行调用,这样以来就很好的解决了window.onload事件冲突的问题。

Obsever进阶应用

下面我们演示一个更加复杂的Obsever模式应用,来自著名的Prototype框架,请先查看代码:

Hello.htm
<html>
<head>
<title>Obsever Demo</title>
<script language="javascript" type="text/javascript" src="Obsever.js"></script>
<script language="javascript" type="text/javascript" src="Controller.js"></script>
</head>
<body>
    
<input id='textbox1' name='textbox1'/>
    
<select id='selElement1' >
        
<option >choose</option>
        
<option value='1' >1</option>
        
<option value='2'>2</option>
        
<option value='3'>3</option>
    
</select>
</body>
</html>

Obsever.js

function $(id){return document.getElementById(id);}
var $A = Array.from = function(iterable) {
  
if (!iterable) return [];
  
if (iterable.toArray) {
    
return iterable.toArray();
  } 
else {
    
var results = [];
    
for (var i = 0, length = iterable.length; i < length; i++)
      results.push(iterableIdea);
    
return results;
  }
}
var Browser={
    isWebKit : navigator.userAgent.indexOf('AppleWebKit
/') > -1
    }
Function.prototype.bind 
= function() {
  
var __method = this, args = $A(arguments), object = args.shift();
  
return function() {
    
return __method.apply(object, args.concat($A(arguments)));
  }
}
if (!window.Event) {
  
var Event = new Object();
}
Object.extend 
= function(destination, source) {
  
for (var property in source) {
    destination[property] 
= source[property];
  }
  
return destination;
}
Object.extend(Event,
{
observe: 
function(element, name, observer, useCapture) {
    
if(typeof element != 'object')
    element 
= $(element);
    useCapture 
= useCapture || false;

    
if (name == 'keypress' &&
      (isWebKit 
|| element.attachEvent))
      name 
= 'keydown';

    Event._observeAndCache(element, name, observer, useCapture);
  },

stopObserving : 
function(element, name, observer, useCapture) {
    element 
= $(element);
    useCapture 
= useCapture || false;

    
if (name == 'keypress' &&
        (Browser.WebKit 
|| element.attachEvent))
      name 
= 'keydown';

    
if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } 
else if (element.detachEvent) {
      
try {
        element.detachEvent('on' 
+ name, observer);
      } 
catch (e) {}
    }
  },
  observers: 
false,
  _observeAndCache: 
function(element, name, observer, useCapture) {
    
if (!this.observers) this.observers = [];
    
if (element.addEventListener) {
      
this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } 
else if (element.attachEvent) {
      
this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' 
+ name, observer);
    }
  }
}
)

Controller.js
function changeHandler()
{
    $('textbox1').value
=this.value;
}
Event.observe(window, 'load',
    
function(){Event.observe('selElement1','change',changeHandler.bind($('selElement1')));}
);

上面代码演示了一个当选择下拉框的时候,调整文本框的值。我们演示了onchange和onload事件的监听,同样的也可以应用到任何DOM节点的各个事件上。但是,你可能说你可以在<select>标签中直接添加onchange事件就可以了,为什么要这么做?

Well,首先这样可以更好的分离代码和视图,就像我上篇文章中讨论的MVC模式,我们应该尽可能的分离代码和视图。尤其是当你构建一个大型的应用程序的时候,例如飞鸽这样的网站,越是可以从中受益。
    
同时通过这种方式,可以设计出一个完整的客户端事件流程。关于JavaScript事件模型的讨论,将是我们后面文章的讨论内容。

注:文中代码部分取自著名的Prototype框架,不过根据行文需要,我做了适当改动 :)
 



Truly 2007-07-31 21:34 发表评论
Visual Basic 9 不完全入门系列(7) : DLinq : 进阶
     摘要: 随着 Beta 2 的发布,无数的新特性涌到程序员的面前。历经千辛万苦,我也安装上了 Visual Studio 2008 Standard Edition Beta 1。这一篇文章随之改变内容,转而描述 Beta 2 中 DLinq 振奋人心的增强。此处仅列出一部分,性能的评估则移交 LINQ 性能分析系列,日后再谈。它们包括更多的谓词支持,加强的设计器支持与其他的许多变化。  阅读全文

随风流月 2007-07-31 17:47 发表评论
NET框架中的 Decorator 和 Strategy 模式
     摘要: 应用场景:net 框架下的TextWriter,HtmlTextWriter,CssTextWriter,IndentedTextWriter 等
先看一下Decorator 模式结构图:
  阅读全文

daizhj 2007-07-31 17:43 发表评论
More Posts Next page »