2006年2月28日

我将Page2的内容通过<object />标签包含在了Page1中:
<object data="Page2.html?userid=1" type=""text/html"" height=""430"" width=""100%""></object>

Page2的内容成功地包含到Page1中,但是却发现在包含Page2的地方出现了滚动条,很难看,想将其去掉。

在网上找了一些方法,有些不好使,不过有个方法非常简单,只要将Page2的body的scroll属性设置为no就可以了。

posted @ 2006-02-28 17:39 雨田美文 阅读(1858) 评论(1) 编辑

    在Web上显示图片,通常都会有图片显示比例问题,如果不给<img />限制width和height,那么如果图片大了就会将整个页面挤乱,图片小了又会使图片失真。
    我的需求如下:
        1、预先定义好图片显示的标准宽度和高度。
        2、如果图片的大小超过了标准定义,那么等比例压缩图片。
        3、如果图片的大小等于标准定义,那么按照标准宽度和高度显示图片。
        4、如果图片的大小小于标准定义,那么不对图片进行任何压缩处理。
    可能是我搜索的关键字不对吧,在网上找了很长时间,才找到,感觉很好使。代码如下
<script language="JavaScript">
<!--
//图片按比例缩放
var flag=false;
function DrawImage(ImgD,iwidth,iheight)
{
    
//参数(图片,允许的宽度,允许的高度)
    var image=new Image();
    image.src
=ImgD.src;
    
if(image.width>0 && image.height>0){
    flag
=true;
    
if(image.width/image.height>= iwidth/iheight){
        
if(image.width>iwidth){  
        ImgD.width
=iwidth;
        ImgD.height
=(image.height*iwidth)/image.width;
        }
else{
        ImgD.width
=image.width;  
        ImgD.height
=image.height;
        }

        ImgD.alt
=image.width+"×"+image.height;
        }

    
else{
        
if(image.height>iheight){  
        ImgD.height
=iheight;
        ImgD.width
=(image.width*iheight)/image.height;        
        }
else{
        ImgD.width
=image.width;  
        ImgD.height
=image.height;
        }

        ImgD.alt
=image.width+"×"+image.height;
        }

    }

}
 
//-->
</script>
调用:
<img src="images/toplogo.gif" onload="javascript:DrawImage(this,100,100)">

posted @ 2006-02-28 09:53 雨田美文 阅读(2524) 评论(0) 编辑

2005年11月17日

    公司现在的项目数据库访问采用主动域对象持久化技术,即在持久化对象中封装数据库操作,而业务逻辑层只管调用持久化对象的接口,不管数据库操作细节。例如:Save一个Employee对象,罗基层客户端只需调用Employee持久化对象的Save()方法就行了。

    但是这样做会是数据层出现大量冗余代码,特别实在查询的时候。如果想通过ID获取一个Employee那么就会有一个GetEmployeeByID()方法,如果又按照Name查找或者想获取所有Employees呢,又会有GetEmployeeByName()和GetAllEmployees()方法。其实他们除了Sql语句不一样,其他都一样。   

    // Get Employee By ID
    private DataSet GetEmployeeByID( string sEmployeeID )
    {
        string sSql = "SELECT * FROM EMPLOYEE WHERE EMPLOYEEID='"+ sEmployeeID +"'";
        DataSet ds = new DataSet();

       // Sql Connection
       SqlConnection conn = null;

       try
       {
        // create connection
        conn = new SqlConnection( GetConnectionString() );
    
        // create command
        SqlCommand cmd = new SqlCommand( sSql, conn );

        // create adapter
        SqlDataAdapter adapter = new SqlDataAdapter();

        // set command text for adapter
        adapter.SelectCommand = cmd;
    
        // open connection
        conn.Open();
    
        // fill data set
        adapter.Fill( ds );
    
       }
       catch(Exception ex)
       { 
            // message
            System.Windows.Forms.MessageBox.Show( ex.ToString(), "Exception Information" );
    
            // rethrow
            throw ex;
       }
       finally
       {
            // close connection
            if(conn != null)
            {
                 conn.Close();
            }
       }

       return ds;
    }

    // Get All Employees
    private DataSet GetAllEmployees()
    {
        string sSql = "SELECT * FROM EMPLOYEE";
        DataSet ds = new DataSet();

       // Sql Connection
       SqlConnection conn = null;

       try
       {
        // create connection
        conn = new SqlConnection( GetConnectionString() );
    
        // create command
        SqlCommand cmd = new SqlCommand( sSql, conn );

        // create adapter
        SqlDataAdapter adapter = new SqlDataAdapter();

        // set command text for adapter
        adapter.SelectCommand = cmd;
    
        // open connection
        conn.Open();
    
        // fill data set
        adapter.Fill( ds );
    
       }
       catch(Exception ex)
       { 
            // message
            System.Windows.Forms.MessageBox.Show( ex.ToString(), "Exception Information" );
    
            // rethrow
            throw ex;
       }
       finally
       {
            // close connection
            if(conn != null)
            {
                 conn.Close();
            }
       }

       return ds;
    } 


    那么有人说了,编写一个共性一点儿的方法GetEmployee()方法,将查询条件作为参数传进去,不就得了。这样是可以解决部分问题,但是又暴露出了另一个问题,那就是逻辑层组织SQL查询条件,使得逻辑层开始知道数据库操作的细节了,加强了逻辑层和数据层的耦合。如果数据库发生了修改,不但要修改数据层的代码,还要修改逻辑层的代码,即没有将数据库的修改对系统造成的冲击压制在数据层,而影响到了逻辑层。
    
    现在我们的问题明确了,提出我们的要求:
    1、减少数据层的冗余代码。
    2、为逻辑层和数据层解耦。
    
    研究上面的代码,你会发现执行数据库操作有两个公共步骤,一是组织SQL,二是执行SQL。

    首先我们将执行SQL的部分封装到SqlExecutor类中,由他来负责SQL语句的执行和返回结果。客户端调用时只是发出执行SQL的请求,不管如何使用ADO.Net操作数据库。它有如下方法:
    
    // 执行Insert/Update/Delete语句,返回执行结果    
    public static bool ExecuteUpdate( string sSql )
    
    // 执行Select语句,返回DataSet
    public static DataSet ExecuteQuery( string sSql )

    // 执行Scalar
    public static string ExecuteScalarQuery( string sSql )
    
    这里应该还考虑存储过程和事务处理,不过作为demo,不再多说。

    其次,就是将SQL的组织进行封装,最理想的是自动产生SQL,这也是NHibernate所能够完成的。也曾想直接使用NHibernate不就得了。但是,这里有三个问题:第一,我们的项目开发周期非常短,进度急,使用NHibernate的风险实在太大;第二,性能问题,构架中间曾势必带来性能上的损失;第三,灵活性,项目中总会出现查询条件非常复杂的SQL语句,例如子查询嵌套,恐到时候为了搞出一个SQL,上下求索而不能。因此,我们想引入NHibernate的思想,并对其进行简化,半自动化产生SQL语句。
    
    让我们来看看平时都是怎样组织SQL语句的:在逻辑层将数据通过参数传入到数据层持久化对象的特定方法中,然后hard code将参数组织到对应的字段上。以保存Employee为例子:
    
    public class Employee
    {
        public string sEmployeeID;
        public string sFirstName;
        public string sLastName;
        
        public Employee()
        {
            sEmployeeID = "0";
            sFirstName = "";
            sLastName = "";
        }
    }
    public bool SaveEmployee( Employee emp )
    {
        string sSql = "INSERT INTO EMPLOYEE (FIRSTNAME, LASTNAME) VALUES ('"+ emp.sFirstName +"', '+ emp.sLastName +')";
        
        // execute sql
        SqlExecutor.ExecuteUpdate( sSql );
    }
    
   我希望的效果是在逻辑层初始化Employee持久化对象,并对其属性进行赋值。再调用Employee的ExecuteUpdate()方法,客户端负责制定所要执行的SQL语句,该语句会在Employee中半自动产生。因此,逻辑层客户端调用代码如下:
  
  // BizLogicObject
  private void SaveEmployee()
  { 
   // new Employee Object
   Employee employee = new Employee();

   // set value
   employee.sEmployeeID = this.textBox1.Text;
   employee.sFirstName = this.textBox2.Text;
   employee.sLastName = this.textBox3.Text;
   
   // save Employee
   bool bResult = employee.ExecuteUpdate( Employee.UpdateSqlTextSelector.SaveEmployee );

   MessageBox.Show("Saving Result: "+ bResult, "Message");
  }

  // Employee持久化对象
using System;

using System.Collections;
using System.Data;

namespace ObjectPersistent2
{
 public class Employee
 {
  #region Public Fields

  // employee id
  public string sEmployeeID;

  // first name
  public string sFirstName;

  // last name
  public string sLastName;

  #endregion

  #region Sql Text Selector: enum
  
  public enum UpdateSqlTextSelector
  {
   SaveEmployee,
   DeleteEmployeeByID
  }

  public enum QerySqlTextSelector
  {
   SelectEmployeeByID,
   SelectAllEmployees,
   SelectEmployeeByFirstName,
  }
  
  #endregion

  #region SQLs
  
  #region Query SQLs
  // Sql Text for select employee by its id
  private string sSelectEmployeeByID = "SELECT EmployeeID, FirstName, LastName FROM Employees WHERE (EmployeeID = @sEmployeeID)";
  
  // sql text for select all employee
  private string sSelectAllEmployees = "SELECT EmployeeID, FirstName, LastName FROM Employees";
  
  // sql text for select employee by first name
  private string sSelectEmployeeByFirstName = "SELECT EmployeeID, FirstName, LastName FROM Employees WHERE (FirstName = '@sFirstName')";
  #endregion

  #region Update SQLs
  // Sql Text for save employee
  private string sSaveEmployee = "INSERT INTO Employees (FirstName, LastName) VALUES ('@sFirstName', '@sLastName')";
  
  // Sql Text for delete employee by its id
  private string sDeleteEmployeeByID = "DELETE FROM Employees WHERE EmployeeID = @sEmployeeID";
  
  #endregion
  
  #endregion
  
  #region Constructors
  
  public Employee()
  {
   this.sEmployeeID = "0";
   this.sFirstName = "";
   this.sLastName = "";
  }
  #endregion

  #region Private Methods
  
  /// <summary>
  /// Functions: select and return corresponding SQL by enum SqlTextSelector
  /// Author: Neo. Liu (2005-11-15)
  /// </summary>
  /// <param name="selector">enum: SqlTextSelector</param>
  /// <returns>string: corresponding Sql</returns>
  private string SelectSqlText( Employee.QerySqlTextSelector QuerySqlSelector )
  {
   string sSql = "";
   
   switch( QuerySqlSelector )
   {
    case Employee.QerySqlTextSelector.SelectEmployeeByID:
     sSql = sSelectEmployeeByID;
     break;
    case Employee.QerySqlTextSelector.SelectEmployeeByFirstName:
     sSql = sSelectEmployeeByFirstName;
     break;
    case Employee.QerySqlTextSelector.SelectAllEmployees:
     sSql = sSelectAllEmployees;
     break;
    default:
     throw new Exception( "Invalid Sql Text Selector." );
   }
   
   return sSql;
  }

  private string SelectSqlText( Employee.UpdateSqlTextSelector UpdateSqlSelector )
  {
   string sSql = "";
   
   switch( UpdateSqlSelector )
   {
    case Employee.UpdateSqlTextSelector.SaveEmployee:
     sSql = sSaveEmployee;
     break;
    case Employee.UpdateSqlTextSelector.DeleteEmployeeByID:
     sSql = sDeleteEmployeeByID;
     break;
    default:
     throw new Exception( "Invalid Sql Text Selector." );
   }
   
   return sSql;
  }


  #endregion

  #region Public Methods
  
  public bool ExecuteUpdate( Employee.UpdateSqlTextSelector UpdateSqlSelector )
  {
   try
   {
    // get sql
    string sSql = SqlTextBuilder.BuildSqlText( this.SelectSqlText( UpdateSqlSelector ) , this );
    
    // execute sql
    return SqlExecutor.ExecuteUpdate( sSql );
   }
   catch(Exception ex)
   {
    System.Windows.Forms.MessageBox.Show(ex.ToString()); 
   }
   
   return false;
  }


  #region Query Methods
  
  public DataSet ExecuteQuery(Employee.QerySqlTextSelector QuerySqlSelector )
  {
   DataSet ds = null;
   try
   {
    // get sql
    string sSql = SqlTextBuilder.BuildSqlText( this.SelectSqlText(QuerySqlSelector ), this );
    
    // execute sql
    ds = SqlExecutor.ExecuteQuery( sSql );
   }
   catch(Exception ex)
   {
    System.Windows.Forms.MessageBox.Show(ex.ToString()); 
   }
   return ds;
  }
  
  #endregion

  #endregion
 }
}

    // Sql Text Builder负责替换Sql语句
using System;
using System.Collections;

using System.Text.RegularExpressions;
using System.Reflection;

namespace ObjectPersistent2
{
 /// <summary>
 /// SqlTextBuilder 的摘要说明。
 /// </summary>
 public class SqlTextBuilder
 {
  
  #region Public static Methods
  /// <summary>
  /// Functions: build and return SQL
  /// Author: Neo. Liu (2005-11-15)
  /// </summary>
  /// <param name="sSql">string: rough sql text</param>
  /// <param name="PObj">Persistent Object</param>
  /// <returns>string: builded sql text</returns>
  public static string BuildSqlText( string sSql, object PersistentObject )
  {
   // sql text
   string sTempSql = sSql;
   
   //
   // parse sql text, get @paramter holder
   //
   MatchCollection matches = GetMatchCollection( sSql );
   
   string sPlaceHolder = "";
   string sFieldName = "";
   string sFieldValue = "";
   
   // loop
   foreach( Match match in matches )
   {
    // place hoder, such as: @N_EmployeeID
    sPlaceHolder = match.Value;

    // table column name, such as N_EmployeeID
    sFieldName = sPlaceHolder.Replace(@"@", "" );
    
    // get field value
    System.Type ObjType = PersistentObject.GetType();

    FieldInfo FieldObj = ObjType.GetField(sFieldName );

    sFieldValue = FieldObj.GetValue( PersistentObject ).ToString();

    // replace
    sSql = sSql.Replace( sPlaceHolder, sFieldValue );
   }
   
   return sSql;
  }

  #endregion

  #region Private static Methods

  /// <summary>
  /// Functions: Get match collection from SQL
  /// Author: Neo. Liu (2005-11-15)
  /// </summary>
  /// <param name="sSql">string: target sql</param>
  /// <returns>MatchCollection</returns>
  private static MatchCollection GetMatchCollection( string sSql )
  {
   Regex RegExp = new Regex( @"@\w+" );
   
   return RegExp.Matches( sSql );
  }

  #endregion
 }
}

初步设想,请大家多提意见。

    
    
    

   

posted @ 2005-11-17 17:13 雨田美文 阅读(1779) 评论(9) 编辑

2005年11月14日

    公司的产品开发使用的是DevExpress的WinForms Collection控件集。当时使用的是2.x版本。现在看到3.x超强的功能,实在是馋人。所以希望能够从2.x升级到3.x。

    但是,公司比较担心升级后会带来版本不兼容的问题,比如,在2.x发布的接口或属性在里3.0里发生了改动。于是我作了如下尝试,据我现在所知道的数据,我觉得从2.x升级到3.x是没有问题的。

    为了方便,先定义一些变量:
            DevExpress2.x版本的TextEdit控件:
                TextEdit1
                TextEdit2
            
            DevExpress3.x版本的TextEdit控件:
                TextEdit3
                TextEdit4

    首先,我想知道,DevExpress 2.x和3.x是否能够同时使用。于是,我在Form1中放置了TextEdit1和TextEdit3,然后,编译、运行。结果成功。但是出现了一个奇怪的问题,那就是:如果在Form1中先拖入TextEdit1(在项目的引用中添加DevExpress.XtraEditor),那么之后拖入的3.x的TextEdit控件都会被认为是2.x版本的TextEdit控件;反过来,如果先拖入TextEdit3(在项目的引用中添加DevExpress.XtraEditor3),那么之后拖入的2.x版本的TextEdit控件都会被认为是3.x版本的TextEdit控件。

    我开始怀疑是VS2003将两个版本的dll给弄混了,因此我又作了如下:
    
    1、我想模仿控件升级的场景,新建Form2,添加2.x版本的TextEdit控件TextEdit1(项目的引用中同时加入了DevExpress.XtraEditor)。
    2、然后,添加3.x版本的TextEdit控件TextEdit3(项目的引用中添加了DevExpress.XtraEditor3)。这时,TextEdit3仍然被作为2.x的TextEdit控件被处理。
    3、编译运行,没有问题。
    4、将项目引用中对2.x版本DevExpress.XtraEditor和DevExpress.Utils项删除,只保留DevExpress.XtraEditor3、DevExpress.Data3和DevExpress.Util3项。
    5、再添加3.x版本的TextEdit控件TextEdit4,我惊奇的发现,此时添加的TextEdit4居然被正确的识别为3.x版本的控件。可是,刚才添加的TextEdit3却仍然被识别为2.x版本的控件。
    6、编译运行,没有问题,TextEdit1和TextEdit3都被编译为2.x的控件,而TextEdit4为3.x的控件。注意,这时,项目的引用中已经不再有对2.x版本dll的引用了,可是2.x版本的TextEdit控件编译运行仍然没有问题,而且行为还是2.x版本的行为。这不正是我们所希望的吗?低版本的控件还是低版本的控件,高版本的控件还是高版本的控件,互不影响。
   
    我觉得其中的规则是:控件按照它拖入时的版本进行编译,高版本控件向下兼容低版本的控件。为了证明这个观点,我将上面的做法反过来,先添加3.x版本的TextEdit3,再添加2.x版本的TextEdit1,删除对3.x版本dll的引用,再添加2.x版本的TextEdit2,运行编译。结果,编译失败,报没有mask属性;这是由于删除了对3.x版本dll的引用,但是在视图设计界面TextEdit3仍然为3.x版本的控件,而TextEdit1和TextEdit2为2.x版本的控件。看来高版本向下兼容低版本。
    
    我后来有将内部的一个项目用DevExpress提供的XtraConverter工具进行了一下转换,速度非常快,不像是修改代码的样子。打开项目的引用,发现有的使用DevExpress控件的项目原先对DevExpress.Editor dll的引用被修改为DevExpress.Editor3,不过,奇怪的是有的使用了DevExpress的控件,却没有修改引用。但是编译成功。虽然运行时失败,不过不是因为DevExpress控件升级。

    好了,综上,我觉得DevExpress WinForms控件集完全能够很好的从低版本升级到高版本,而不必修改原来的程序。当然,这样下结论比较毛躁,希望各位网友提供线索。
   

posted @ 2005-11-14 17:30 雨田美文 阅读(1326) 评论(8) 编辑

2005年11月3日

 

前言

没能和您深谈,所以不太明确您的意图。这个题目是我自己拟的,希望能够接近您所关心的话题。

说实话,我对硬件平台没有什么经验,因此,也提不出太多的看法。不过,对Web平台和软件架构还是有一点体会,希望能够和您分享。

刚开始,我在努力猜测您的意图,不过我也同时发现这很难,而且风险很大。我不太清楚您到底需要什么,只好以不变应万变,我会结合自己所经历过的项目,去谈谈对Web平台和软件架构的一些看法,这也是我现在能够为您做的了。

关于Web平台

       说到Web平台,我想谈谈瘦客户端(Thin Clients)和胖客户端(Fat Clients)。因为这对于Web平台,无论是使用,还是开发,都是具有革命性意义的。

       让我们先看看瘦客户端吧。我们在享受着它的易于部署、易于维护,客户端成本为零的好处的同时,也为它糟糕的用户体验和复杂的开发所头痛。我是个软件工程师,因此,对于Web开发中很多恼人的问题也感触颇深。例如,没有很好的IDE环境,没有丰富的控件支持,总得刷新页面等。

有时,看着C/S结构的开发人员们,满是羡慕,如果我们也有类似于Visual Studio那样的IDE环境,如果我们也有那么多能够托托拽拽,设置几个属性就OK的控件,如果不用老是刷新页面,那该多好呀。每到这时,就安慰自己,你看他们升级客户端程序多费劲呀,哪像咱们,一处发布,任何地方都能用。

       瘦、胖客户端各有各的优势和缺点,如果能结合他们的优点就好了。于是,胖客户端的Web程序出现了,这在当时,着实让我兴奋了很久。当我看到MacromediaFlex平台时,我真是激动万分,原来Web程序还能这样:不仅结合了C/S结构丰富的用户体验,很好的控件支持,同时还保留了Web方式的易于发布的优质。

       在迷了一段时间的胖客户端后,发现它也不是万能的,也有其适用的范围。抛开开发,对于用户,胖客户端所带来的最大的好处在于丰富的用户体验,用户看到的不再只是简单的表格,不必总是刷新页面。因此,胖客户端比较适用于对用户交互要求较高的情况。例如,企业内部的信息管理系统、网络相册等。而对于没有太多用户交互,用户的大部分操作只是View的情况,胖客户端就显示不出它的优势了。例如,新闻网站还是用瘦客户端比较好。

       OK,对于胖客户端和瘦客户端我就谈到这里。下面我还想就Web平台的两大主流技术:JSPASP.Net说两句,也是最近才有的感想,因为自己这段时间从Java平台转到.Net平台,对两个技术有个简单的对比。

       JSPASP.Net最大的感触是,JSP在易用性、控件支持和用户体验上远不如ASP.Net,但是它却有着ASP.Net所没有的、优异的框架组织。ASP.Net缺乏的是如何将这些优异的控件、组件有机的组织起来的框架,而JSP却恰恰相反。ASP.Net就像是一个明星球队,每个球员都很棒,但却缺乏一个很好的组织和协调;而JSP像是一个没有明星的球队,每个队员都不是很强,但是却有惊人的组织和协调。

       好了,Web平台就谈到这吧。

关于软件架构

       刚入行的时候,关心的是语言语法,后来研究控件、组件,再后来才发现,对于大型企业应用,真正的问题,不是某个算法如何优异,某个控件怎样使用,而是如何将这些单元有机的组织起来,实现良好的可维护性、可扩展性等,这也是我理解的软件架构。

       谈到软件架构,我觉得应该说说应用程序的分层,我觉得分层是软件架构的表现,也是实现良好的可维护性和扩展性的方式。

       还是老规矩,以我经历的项目来谈谈软件分层的好处和坏处。

       我经历的第一个Web项目,界面层和数据层是绑定在一起的,其实也是当时最传统的做法,在界面页上嵌JSP数据库查询代码,htmlJSP混合在一起。例如,要显示一个列表,就用JSP查出结果集,然后用<tr><td>作循环。

       很显然,这样够直接,开发人员不用什么特别的设计就能够快速开发出东西。可是,问题呢?好多呀。例如:

l         代码的可读性很差,html中掺杂这数据代码,还有逻辑代码,你读代码就一个感觉――乱,想找个地方都找不到。

l         界面和数据代码、业务逻辑之间耦合,复用几乎为零。当我们想更改页面风格时,我们不敢改,为什么,因为我们不光要修改界面层,还有修改数据、逻辑代码,真是“牵一发而动全身”。当我们在另一个地方用到相同的界面,只是数据不同时,我们只能重新做一个界面再加数据代码,因为我们根本无法将界面从高耦合的代码中玻璃出来。

很庆幸,我们通过JDBC将数据库和应用程序的耦合关系断开了。它的好处在我们将数据库从Oracle 8i升级到Oracle 10g时体现出来。当我将后台数据库更换后,居然不用修改任何代码就能够Run起来。我觉得这也是分层能够带来的好处之一,将修改限制在某一层中,而不会影响其他层的东西。

总结了一下,觉得分层会在可维护性、可扩展性、可复用性上得到很好的效果。但是,想要得到它的好处,就要为它付出代价。分层对开发和设计人员都提出了更高的要求,而且调试时也会遇到困难。不过,我觉得这是值得的。

后来,研究了一些设计模式,读了一些关于SpringHibernate的书,为Java平台下有这样优异的框架而惊叹。

随着自己理解的加深,感觉无论是设计模式还是中间件、框架都是在不同程度上构建中间层,进行解藕。

好了,我谈完了,一些思想还不成熟,也不一定正确。不过,我仍然希望您能够满意,期望和您交流。谢谢。

 

刘洋

2005-11-3

posted @ 2005-11-03 23:30 雨田美文 阅读(3121) 评论(10) 编辑

2005年10月19日

大家都知道,在面向对象的OOP语言设计中,为了增加代码的复用,有两种方式:一种是New一个Class的实例,另一种则是继承某一个Class。

昨天,遇到了一个问题,我和另一个同事提出了两个不同的解决方式,从而引发了对实例复用和继承复用的讨论。

问题如下:
系统中出现了一个UI,在不同的地方都会得到使用,界面相同,只不过逻辑控制不同。例如,对于New和Edit界面,其实它们是同一个UI,但是却有着不同的逻辑操作,比如,New界面没有不用加载数据,而Edit需要加载数据。

OK,问题确定。我给大家介绍一下我们讨论的过程。

1、首先,我们发现New和Edit虽然UI相同,但是却无法复用。原因在于Edit的UI中混合了太多的逻辑控制代码,UI和逻辑控制绑在一起,我们根本无法将UI剥离出来,进行复用。因此,我提出,应该将UI和对UI的逻辑控制分开,不要将逻辑控制代码Hard Code到UI上,而是构架中间层,将UI的逻辑控制剥离出来,以实现UI和逻辑控制代码的复用。

2、这时,一个同事提出了另一个思路,在UI上不加入逻辑控制代码,然后继承两个子类Edit UI和New UI,然后分别在Edit UI和New UI上加入逻辑控制代码,而且我们可以新增一些控件。这样也能够实现对父类UI的复用。

    对于这种方法,我当时也觉得可以实现我们的复用需求,但是,后来想想,有2问题:
    
    问题一:如果Edit UI和父UI完全相同,OK,这样做是能够实现父UI的复用的。但是,既然完全没有变化,为什么不直接使用原来的UI,而非得Clone一个相同的子类呢?你可能说,我添加了逻辑控制代码,不算改变吗?我觉得还是有问题,将UI和逻辑控制绑定在一起,必然降低逻辑控制代码的复用性。
    
    问题二:如果Edit UI在父UI的基础上进行修改,有和逻辑控制代码绑定在一起,那么如果我想复用Edit UI怎么办呢?
    
总结:
1、将UI和逻辑控制代码分离,能够很好的实现UI的复用和逻辑代码的复用。
2、如果不需要在原来的Class上进行扩展、变异,那么直接用实例比较好,如果有“变异”,那么使用继承比较好。

完成。

posted @ 2005-10-19 13:25 雨田美文 阅读(162) 评论(0) 编辑

2005年10月18日

摘要: 自己在写简历,有些心得,分享给大家。 简历设计思想1、 以工作经验为核心。2、 从三方面介绍自己的工作经验:a) 第一,项目经验,体现行业、平台和技术背景;b) 第二,工作范围,即在以往的工作中你都担当什么样的角色,完成什么工作。c) 第三,技术技能。3、 体现双向选择原则,既要提供雇主所关心的信息,又要说明自己的期望。阅读全文

posted @ 2005-10-18 14:25 雨田美文 阅读(134) 评论(0) 编辑

2005年10月16日

摘要: 我们公司是一家小型软件公司,软件开发过程中存在着一些问题,总结了一下,share给大家。我所总结的是软件开发过程的一些技术问题,不包括软件工程。首先,总结一下指导思想的问题,之所以将其放在首位,是因为很多的问题都是有其衍生的。1、过于重视软件过程,却忽视技术因素对软件过程的影响。2、认为满足今天的需求就OK,从不为明天明天的维护留后路。随心编写代码,拼凑需求功能,没有设计,没有结构,结果后期维护起...阅读全文

posted @ 2005-10-16 13:18 雨田美文 阅读(704) 评论(5) 编辑

2005年10月14日

摘要: C# Project ToolsThis project is converted and modified from the VB.Net Project Tools. Since I need a Common Class in C# projects replacing VB.Net's Common Module (including the source code in C# rathe...阅读全文

posted @ 2005-10-14 11:29 雨田美文 阅读(1174) 评论(0) 编辑

2005年10月12日

摘要: 今天做公司的项目,遇到Validate Number,却发现C#居然没有类似IsNumeric()的函数,不知C#的设计者是怎么想的。只好自己写函数校验Number,在网上看到一些写法,感觉比较好:staticboolIsNumeric(stringstr){System.Text.RegularExpressions.Regexreg1=newSystem.Text.RegularExpress...阅读全文

posted @ 2005-10-12 17:27 雨田美文 阅读(1548) 评论(1) 编辑