首页 > 开发 > 综合 > 正文

架构设计之首部曲

2024-07-21 02:17:07
字体:
来源:转载
供稿:网友
系统采用|b/s结构,共分三层,分别是数据访问层,业务规则层,web外观层。它们各自有自己的职责,各自为政又互相配合从而形成一个软件的整体功能系统,数据访问层的职责是负责对数据源的存取(这里的数据源是指sql server 2000),业务规则层负责的是对数据按照业务流程的处理,web外观层负责向用户提供交互的接口,只负责输入输出数据。这样设计是很普遍的,它提供了一个较好维护的体系。

设计:

1) 数据访问层:

很多人愿意在这一层封装大量的sql脚本以简化上层的设计,但是这样的设计并不合适!业务一般情况下会有变化,如果把sql脚本“硬编码”在一起,修改时不得不修改程序的源代码。而用户那里一般只有打包的二进制程序!所以较好的做法是将对数据的操作的脚本放在外面,一般是放在离数据近的地方,如sql server上,这里我们把它

编写成存储过程放在sql server服务器上。编写成存储过程有这样的两个好处:第一,业务改变时,只要改存储过程即可。第二,没有必要将大量的脚本通过网络传输到数据库服务器解析执行,给网络带来很大的负担。而是只是调用一个存储过程名而已,大大降低了网络负担和中间层的负担。 如:执行添加用户的操作

create procedure dbo.user_create

@realname varchar(50),

@deptname varchar(50),

@hashedpassword varchar(50),

@tel varchar(50),

@address varchar(50),

@dutyname varchar(50),

@username varchar(50)

as

begin tran

insert into [user] (username,realname,deptname,hashedpassword,tel,address,dutyname) values(@username,@realname,@deptname,@hashedpassword,@tel,@address,@dutyname)

if @@error!=0

begin

rollback

return 0

end

else

begin

commit

return 1

end



对于执行存储过程和维护和数据库连接状态的方法(如:execsql(string sql),open())应当封装在一个公共类中共其他类使用,而不是每个类都有自己的数据库方法!这样的意图是可以减少重复依赖,而且如果将这个共享类的方法抽象出来成为一个接口,让所有用到他的类使用这个接口,在共享类发生变化时,使用它的类并不知晓这些变化,减少了依赖就意味着更好地适应变化!

如:

public class database : idisposable ,isqldatabase(参考于codeplus)

{

private sqlconnection con;

private dbconfig m_config=dbconfig.instance;

public int runproc(string procname)

{

sqlcommand cmd = createcommand(procname, null);

cmd.executenonquery();

this.close();

return (int)cmd.parameters["returnvalue"].value;

}

public int runproc(string procname, sqlparameter[] prams)

{

sqlcommand cmd = createcommand(procname, prams);

cmd.executenonquery();

this.close();

return (int)cmd.parameters["returnvalue"].value;

}
.......

}

接口:

public interface isqldatabase

{

int runproc(string procname) ;

int runproc(string procname, sqlparameter[] prams) ;

void runproc(string procname, out sqldatareader datareader) ;

void runcommand(string command,out sqldatareader datareader);

void runproc(string procname, sqlparameter[] prams, out sqldatareader datareader) ;

sqlcommand createcommand(string procname, sqlparameter[] prams) ;

void open();

void close() ;

sqlparameter makeinparam(string paramname, sqldbtype dbtype, int size, object value);

sqlparameter makeoutparam(string paramname, sqldbtype dbtype, int size);

sqlparameter makeparam(string paramname, sqldbtype dbtype, int32 size, parameterdirection direction, object value);

}

对于连接信息,如连接字符串不应在所有用到数据库的地方出现,负责在部署时不得不在所有的类中调整!所以把它方在xml配置文件中是明智的(分成集成和混合安全性),再用一个类管理它即可.

xml文件的内容:



<?xml version="1.0" standalone="yes" ?>

<newdataset>

<dbconfig>

<servername>gaolei</servername>

<machine>gaolei</machine>

<database>oa</database>

</dbconfig>

<dbconfig>

<servername>gaolei</servername>

<uid>sa</uid>

<pwd></pwd>

<machine>gaolei</machine>

<database>oa</database>

</dbconfig>

<dbconfig>

<logcount>100</logcount>

</dbconfig>

</newdataset>。

对于数据实体层,它负责传递数据,是各层交换数据的地方。设计时应考虑这样几个因素:

第一:性能,交换数据的地方必须要求交换快、占内存少.

第二:业务规则类可以有效地使用他们。

第三:有利于界面部分使用它们,即要能和用户控件绑定在一起使用,帮助简化界面的开发。

为了满足第一要求,可以将实体的值域上移放在基类中,这样两个类为继承关系又各负各则。基类(数值类)的实例数与其子类(方法类)实例数不成比例,基类实例数总是大于方法实例数,一般是n:1,这样消除了没有必要的内存开支,大大提升了性能。对于有些方法参数列表太长,就可以使用基类对象代替。

方法类集成了常用的数据处理方法,所以一旦业务规则类使用它,可以大大简化规则类的复杂度,设计者可以集中精力设计规则类而不必同时考虑实体类的问题。由于值域上移,把值域做成属性,界面上的控件将天生支持对这些属性的绑定。(.net控件的特性)

实体类:

(数值类)

public class logrow:marshalbyrefobject,icomparable

{

protected string m_operatetype;

public virtual string operatetype

{

get { return m_operatetype;}

set { m_operatetype=value;}

}

..........

public logrow()

{// todo: 在此处添加构造函数逻辑



}

#region icomparable 成员



public int compareto(object obj)

{

logrow row=(logrow)obj;

if(row.operator.equals(this.operator)&&row.operatetype.equals(this.operatetype)&&row.operatetime.equals(this.operatetime)&&row.contents.equals(this.contents))

return 1;

return 0;

}



#endregion

}

方法类:

public class log:logrow

{

public log()

{

}

public bool create(string operatetype,string contents,string operator,system.datetime operatetime)

{

database data = new database();

sqlparameter[] prams = {

data.makeinparam("@operatetype",system.data.sqldbtype.varchar,50,operatetype),

data.makeinparam("@contents",system.data.sqldbtype.varchar,255,contents),

data.makeinparam("@operator",system.data.sqldbtype.varchar,50,operator),

data.makeinparam("@operatetime",system.data.sqldbtype.datetime,8,operatetime)

};

int reval = data.runproc("log_create",prams);

data.close();

data.dispose();

if(reval==1)

{

return true;

}

else

{

return false;

}

}

public bool create(logrow logobject)

{

return this.create(logobject.operatetype,logobject.contents,logobject.operator,logobject.operatetime);

}

public bool delete(system.datetime operatetime)

{

database data = new database();

sqlparameter[] prams = {

data.makeinparam("@operatetime",system.data.sqldbtype.datetime,8,operatetime)

};

int reval = data.runproc("log_delete",prams);

data.close();

data.dispose();

if(reval==1)

{

return true;

}

else

{

return false;

}

}

.......

}

2) 业务归则层:

要有自己独立的自定义异常类,对于业务方法要适当使用多线程提升性能。最好使用teampletemothed模式集成流程和适应未来的业务变化或者将方法设置成virtual!

public class ommanager

{

private user user;

private userrole userrole;

private role role;

private rolepopedom rolepopedom;

private string m_currentusername;

private string m_currentpassword;

public ommanager(string currentusername,string currentuserencryptedpassword)

{



user=new user();

userrole=new userrole();

role=new role();

rolepopedom=new rolepopedom();

if((new securityvalidate()).validator(currentusername,currentuserencryptedpassword))

{

this.m_currentusername=currentusername;

this.m_currentpassword=currentuserencryptedpassword;

}

else

{

throw new securityexception("无效用户名/密码");

}

}

public virtual string newuser(userrow newuserdata, string[] assignedroles)

{

string m_hashedpassword=stringencryptor.encryptor(newuserdata.hashedpassword);

newuserdata.hashedpassword=m_hashedpassword;

if(user.create(newuserdata)&&userrole.create(newuserdata.username,assignedroles))

{
//todosomething
}

return null;

}

........}

3)web界面层:要使用规则层的方法执行业务功能,但并不是什么都要通过规则层,而是数据需要业务处理的就引用规则层方法,如果业务上不需要处理(如:填充一个下拉列表)就可以直接使用数据访问层,这样可以减少没必要的性能开支。对于安全性,就是要使用规则类必须经过验证。对于性能可以使用asp.net的缓存技术解决


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表