三层式开发中的层次划分讨论

扩散模型训练新发现:Self-Flow性能提升源于数据扩增策略 数据扩增是深度学习中的基础技术,通过在训练过程中对原始数据进行变换来增加样本多样性。其核心原理是通过几何变换、颜色调整等操作创建虚拟样本,提升模型的泛化能力。在扩散模型特别是DiT架构中,数据扩增技术能够在不增加标注成本的情况下显著改善生成质量。Self-Flow方法的最新研究表明,其性能提升主要来源于精心设计的数据扩增流水线,而非传统的自监督学习组件。这种时序感知的扩增策略与扩散模型的训练过程深度集成,在图像生成、领域自适应等场景中展现出卓越效果,为有限数据条件下的模型优化提供了新的技术路径。 阅读详情

先举一个曾经在哪本书上看到的例子:现在你想在1米宽的小溪上建一座桥,你会在上面放块木板就完了。如果想在宽一点的小河上建这桥,你就需要计算木材用料,价格等,如果需要别人帮忙,你还要多一些图纸什么的让别人理解你的想法。现在你要在大江上面建桥,你需要有整体的计划,包括各个方面,比如将来可能的收费和利益分配等问题。

这里讲3层式,其实是针对“大江上面建桥”来的,对于1米宽的小溪,在实际中可能一点用都没有。不过现在我不可能去拿个长江大桥作例子来讲,所以这里还是用这条简单的小溪,讲讲怎么建桥。之所以讲这么多废话,是为了防止部分人看完此文之后“小小一个东西,搞那么麻烦干什么。。”其实这里讲的不是具体的这个例子,而是分层的思想,理解这点非常重要。

下面我就我们大家日常见最多的例子来讲,就是“用户登录”的例子。这个例子很简单,但是麻雀虽小五脏俱全。从数据访问到业务规则到界面全有了。

本文分2个部分,如果只想研究面向对象的思想,对实现已经熟悉,可以跳过第一部分。

第一部分

 

新建一个空白解决方案。然后:

“添加”-“新建项目”-“其他项目”-“企业级模版项目”-“C#生成块”-“数据访问”(数据层,下简称D层)

“添加”-“新建项目”-“其他项目”-“企业级模版项目”-“C#生成块”-“业务规则”(业务层,下简称C层)

“添加”-“新建项目”-“其他项目”-“企业级模版项目”-“C#生成块”-“Web用户界面”(界面层,下简称U层)

右键点“解决方案”-“项目依赖项”,设置U依赖于D、C,C依赖于D。

对U添加引用D、C,对C添加引用D。

到此为止,一个三层的架子建立起来了。我上面说的很具体很“傻瓜”,知道的人觉得我废话,其实我这段时间很强烈的感觉到非常多的人其实对这个简单的过程完全不了解。虽然不反对建2个“空项目”和1个“Asp net Web应用程序项目”也可以作为3层的框架,而且相当多的人认为其实这些“企业级模板项目”其实就是个空项目,这是一个误区。没错,企业级模板项目你从解决方案资源管理器里看它是个什么也没有的,但是你可以用记事本打开项目文件,看见不同了吧??有些东西在背后,你是看不见的,不过系统已经做好了。也就是说,如果你在C层里的某个类里“using System Data SqlClineit”,或者使用一个SqlConnection对象,编译时候不会出错,但是会在“任务列表”里生成一些“策略警告”,警告你在C层里不要放应该放在D层的东西(虽然就程序来说没错,但是可读性可维护性就打了折扣)而这种功能,空项目是无法給你的。

 

我们知道建桥需要砖块,应该是先准备好砖再来建桥,不过为了讲解上的顺序性和连贯性,简单性。我们先建桥,建的过程中需要砖块再现做,这样就不会多出来“桥不需要的东西”。注意在实际中,还是应该先准备砖块。

 

U层其实就是桥,C层是砖块,D层是原料(石头、沙子)。这也解释前面为什么U层要引用、依赖D层(而不是U对C,C对D的层次),因为桥除了需要砖头,其实也需要石头沙子。

我们在U层建一个Login aspx(这里插入一句,我不喜欢去把系统自动生成的WebForm1 aspx拿来改成login或index或直接删除,我一般留着它当测试代码用,等到整个系统冻结再把它移除就可以了。)添加1个TextBox(id=txt),一个DropDownList(id=ddl),一个Button(id=btn)。其中DropDownList用来选择用户名,button是提交按钮, TextBox用来输入密码。

现在我们必须要添加的代码分为2部分: 1、Page_load时对ddl的初始化。2、btn的click处理。

1:

private void Page_Load(object sender, System.EventArgs e)

{

if(!IsPostBack)

{

this.ddl.DataSourse=DataManager.GetOneColunm(“User”,”uid”); //讲解1

this.ddl.DataBind();

}

}

2:

private void Btn_Click(object sender, System.EventArgs e)

{

string uid=this.ddl.SelectedValue;

string psw=this.txt.Text;

if(psw =””)

     MessageBox(“空密码!”);

else

{

     User theUser;

     try

     {

          theUser=new User(uid); //讲解2

     }

     catch(Exception e)

     {

  MessageBox(e. Message);//讲解2

  return;

}

if(theUser.CheckPsw(psw)) //讲解3

{

  theUser.SetSessions();

  Response.Redirect(“……………..”);  //登录成功! 

}

else

{

  MessageBox(“密码错误!”);

}

}

}

 

 

讲解1:DataManager 是D层中的一个类,提供常见的数据操作。GetOneColunm(string Table,string Colunm)方法返回一个只有1列的DataTable,值为数据库中表名为Table,的Colunm列。

public class DataManager

{

public DataManager()

{

}

public static DataTable GetOneColunm(string Table,string Colunm)

{

     //此处省略相关代码。返回指定表指定列

}

}

其实这个地方演示的是在U层直接绕过C层访问D层的例子,因为该结构逻辑上很简单,而且获取用户名并不是现实社会中的业务逻辑的一部分(仅仅是界面需要,因为在这里其实用成2个TextBox的话完全不需要这一步)

讲解2:定义一个User类的实例。User类的定义可能如下:

public class User

{

public User(string uid)

{

     if(DataManager.IsIn(“user”,”uid=’"+uid+”’”))

          throw "用户不存在";

     else
              //User()其他初始化;

}

public bool CheckPsw(string psw)

{

     if(DataManager.IsIn(“user”,”uid=’"+uid+”’ and psw=’”+psw+”’”))

          return true;

     else

          return false;

}

}

注意到用户类构造函数中用了个throw来抛出用户不存在的异常,在下面catch的时候用MessageBox(e. Message);来弹出“用户不存在”的错误。这里其实也是为了演示一个层间传递信息的手段,异常也是一种手段,虽然在这里其实可以有其他方式比如返回值,引用参数之类的直接用一个方法来获得用户是否存在的信息,没必要放在构造里,我这么做只是为了演示传递过程,在后面的有讨论这种用法在分层模式下某种特殊情况的应用以解决一些问题。这个类里又用了DataManager类的一个静态方法IsIn(string Table,string str)该方法其实其实是执行 “select * from Table where str”

这个Sql语句并在返回空的时候方法返回false,否则返回true。一个很简单的方法。这里演示了C层对D层的调用。

 

顺便说一句,因为在VS.Net中,项目的名称会默认地成为项目中的namespace,可以通过把所有自动生成的代码中的namespace改为“解决方案名称”来使3个层可以无缝地自由调用。或者在调用的地方using一下其他层的空间名,看个人喜欢了。比如上面的Login.aspx.cs里需要using2个,而User.cs里要using一个。

讲解3:这里的检查用户密码同样用到User类的一个方法CheckPsw()而这个方法 又用到了IsIn()这里就不多说了。

大家注意到我们在U层的页面里用MessageBox()方法来弹出对话框,其实这个方法写在PageBase.cs里,是U层的另外一个文件,继承Page类,Login类又继承它,这个方法其实是把Response.Write(“<script>alert(/“”+ msg+“/”)</script>”)封装起来了。

 

 

到此为止,登录结束,例子的实现也说完了。不过只讲了“然”,没有讲“所以然”。下面开始讲“所以然”。

第二部分

 

作为对比,我们使用一个不面向对象的,不分层的Asp式的Aspx相同登录作为对比。具体的Asp代码我就不写了,反正登录哪都有。先来看看他们2者发生的遭遇(这是不幸的,却偏偏是经常发生的):

1、  项目经理突然说“不用SqlServer了,换成Access”(正版费用问题)。看看2边分别发生什么:3层这边(A),把DataManager类里的连接改改(在实际情况下,极可能其实是改它的基类,它本身不用改),Web.config中把字符串换掉就完了。Asp式那边(B),同样要改Web.config,同样要改连接什么的,修改量在这个具体的“小溪”例子上几乎相同,在“大桥”例子上B应该会稍微多改点,不过也不会多很多。但是!请注意一点,我们在修改代码的时候,主要时间和精力不是花在“改”这个动作上,而是花在“要改什么地方”上和“寻找需要改的地方”上。在“大桥”上,B需要花费多的多的时间,对大部分文件进行查找和替换。A则仅仅在数据层里,另外2个层不需要任何修改。从这个角度出发我们想到2点原则:

a)    数据层必须要能够保证数据库的变动(任何结构变动、类型变动)对其余各层的不透明性。也就是数据库怎么变,其他层绝对不应该变哪怕1行代码!(web.config是整个应用程序的配置,虽然在物理上存在于U层的文件夹中,但个人更愿意认为它是独立的不属于任何层的,所以这里不计它)

b)    数据层越小越好(如果没有这点原则,我们把整个所有的东西都放在数据层,那当然数据库变动对外面无影响――因为外面几乎没东西――但是这显然不可行)。而且因为前面我们说了,大部分时间花在“找”上面,你小点,找起来也容易点。

2、  客户突然提出B/S版的不好,要换成C/S版的。对于(B)来说,这是晴天霹雳!!他的所有工作都要重新做,(或者几乎所有工作),虽然他有很多代码还可以用,不过他在未来一小段时间就必须不断在“复制-粘贴”中使用以前的代码。(A)发生了什么??如果你细心看会发现(A)之需要新建个项目“Windows用户界面”(和前面一样,添加引用,项目依赖),拖几个控件到上面,把控件名字起成txt,ddl,btn,然后把click代码和Pageload代码复制过去,(居然。。。)连1行代码都不需要修改!!!!当然,这是比较极端的例子(win和web都有TextBox,DropDownList,Button3种控件,而且我们在PageBase里定义的方法MessageBox()又刚好和win里面方法同名。。。)不过尽管有这么多巧合我们仍然可以也愿意相信,在“大桥”上,(A)将比(B)少做很多工作。从这个角度出发我们又想到2点类似原则:

a)    界面层应该保证界面的任何变化都不需要修改其他层的内容(不管这个具体的例子把ddl改为另外一个TextBox,或是把B/S改为C/S)

b)    界面层越小越好(理由同上。)

3、  除开了界面层和数据层,(如果你的方案中只有3个层的话)剩下的就都是逻辑层的内容了。所以和前面的相对应,我们可以得出结论:

a)    逻辑层应当不受数据库和界面变动的影响而需要修改。

b)    逻辑层越大越好(因为另外2层越小越好。。。)

 

有了最基本的原则,我们应该来讨论下,根据原则,要怎么分层的问题:

1、  PageBase.cs 应该放在哪个层?根据上面的原则,应该放在C层。但是实际上我习惯放在U层,或者放在另外一个(第4个层,通用底层,在比数据层还低的位置)层里。到底放在什么地方,我最开始的做法是在C层,因为按上面归纳的原则,就应该放在C,但是后来一段时间我习惯于“四层式”之后就把它放在通用底层(下简称B层,该层同时也放如本来在D层中的SqlHelper类等,包括原来3层中所有“通用”的类,这里通用的意思是说其他系统也可以用的到而不需要修改,这个层通常不用解决方案名称而用公司、小组名称等作为namespace,在有新项目的时候在建解决方案的时候就可以“添加现有项目”,简单的加进去并不断积累,实践中对提高效率和代码重用有比较大作用。)不过如果只有3层,我现在倾向于把PageBase放在U层。主要因为最近一段潜心研究面向对象的分析设计的心得。说起来又是一大匹布没完,不过我又在前面的“原则”上加1条:“如果某个类,仅为了某层的某种特殊实现而存在,那么它必须放在该层”,比如PageBase是为了U层的特殊实现(B/S实现)而存在,又比如SqlHelper是为了D层的特殊实现(SqlServer数据库)而存在。所以对应的,它们必须分别放在U层和D层(如果不加这条的话按前面他们都该放在C层,因为C层越大越好,而且数据库和界面的变动不需要改动这2个类-虽然它们可能因改动而没有用了,不过还是不需要去修改它们)

2、  Oldjacky曾经和我谈到一个问题:Datagrid中允许作删除操作,但是如果当前仅余下最后一条记录,则不允许这个删除操作!那么该删除应该放在C层还是D层还是U层?我觉得应该从另外一个角度来考虑:

a)    这种“不允许”是“业务规则的不允许”(比如表内的数据表示当前在店里的职员,删除表示职员离开店里-可能去拿货什么的,添加表示职员回来,当柜台只有一名职员时,显然他绝对不能离开去送货),这个时候,此“禁止删除”的操作应该产生在C层。

b)    这种“不允许”是“程序实现的不允许”(比如当这里为空的时候会引起其他地方比如ToString()方法产生“未将对象的引用设置到对象的实例……”的错误,或程序设计者或项目经理的主观愿望希望它“不允许”以此来减少工作量或简化程序)。这个时候,此“禁止删除”可以放在U层(比如上面说的ToString)或D层(比如违反数据库约束)

3、  细心的人可能会发现,前面的登录例子里,用户一共可以获得3种弹出错误分别是“空密码”“密码错误”“用户不存在”,而其中前2个是在U层里做的,“用户不存在”却是在C层里做的(我是指这个字符串)还是开始说的建桥,我这里是用“小溪建桥”来讲解“大江建桥”所以故意在这里转了个没用的圈,就像在计算小溪上这块木板到底够用多少年,其实对小溪没什么意义,只是为了讲解大桥需要而加上去的,毕竟大桥需要这种考虑。我这里假设“用户不存在需要弹出提示”是一种业务逻辑上的需要,而“未输入密码需要提示”则不是业务规则需要(比如实际业务中可以允许空密码,但是项目经理不同意,说一定要密码)在这个登录例子中其实根本没有什么问题,但是在大项目里,如果这个东西不是业务规则的需要,就不应该放在业务层,如果是一种业务规则,就要放在业务层。有助于业务模型与现实实体的衔接,也有益于业务逻辑更好地表现现实实体的特征。

 

到此为止,我再次归纳出我们的最终的原则:

1、  如果某个类,仅为了某层的某种特殊实现而存在,那么它必须放在该层。

2、  数据层应当在保证数据库变化对其他层不可见的前提下尽量小。

3、  界面层应当在保证界面变化对业务逻辑层不影响的前提下尽量小。

4、  如果某个类不是业务规则的需要,就不应该放在业务层,反之亦然。

5、  逻辑层应当在保证数据库或界面变化不会造成自身影响的前提下尽量大。

 

以上5点如果发生冲突,在找平衡点的时候,前面的要高于后面的。比如1和3冲突的时候更倾向于使用规则1。

第二部分结束

 

有一点应该是“编程代码习惯”和“面向对象”的范畴,不过因为和分层有些关系,所以也说一下。“如果你的代码,自己把它翻译成中文并加必要的标点符号后,其他不懂程序的人看了仍然觉得很乱,那么你很可能层没分好”。比如前面的btn的click:

{

字符串 用户名是 下拉框 选择值;

字符串 密码是 输入框 值;

如果 密码是 空

   对话框(密码空!);

否则

{

   用户 这用户;

   尝试

{

这用户 是 新的 用户(用户名);

}

捕捉(错误)

{

对话框(错误 消息);

返回;

}

如果 这用户检查密码(密码)

{

这用户 设置状态;

响应 重定位(“。。。。。”);

}

否则

{

对话框(密码错误)

}

}

代码最好能让不懂的人也能看懂到底在干什么。

 

最后,oldjacky的Datagrid删除的例子“删除”显然在D层,但是不允许却可能在C或U,如果在U没什么说的了,如果在C,那么这种“不允许”的一个比较合理的实现方法就是在C层里遇到这种情况throw一下。当U层里catch到该throw的时候,禁止删除操作,这样当2个层同时有原因引起禁止时,可以从代码一眼看出这种禁止的来源。类似于前面的2种弹出错误。

 

Microsoft.NET Remoting权威指南 .net remoting 经典书籍 英文版(PDF)<br> 立即下载

相关推荐

乐鑫ESP32-C6产测全流程:RAM固件测试与阈值校准实战指南

Wi-Fi模组量产测试是保障IoT设备射频性能与硬件可靠性的关键环节,其核心在于基于RAM的无损固件加载、可配置的阈值判定机制及多工位协同控制。该流程依托串口协议与结构化配置(如JSON阈值文件、.bin测试固件),实现RF性能(fb_rssi、tx_power)、GPIO导通性、Flash ID识别与固件版本校验等原子化测试项的自动化执行。技术价值体现在避免Flash擦写风险、支持动态温补与在线学习校准,并无缝对接MES系统实现质量数据闭环。典型应用场景包括ESP32-C6/C3/S2等乐鑫全系Wi-Fi

weixin_35756690的博客 311

(绝对原创)三层式的层次划分

三层式开发中的层次划分讨论先举一个曾经在哪本书上看到的例子:现在你想在1米宽的小溪上建一座桥,你会在上面放块木板就完了。如果想在宽一点的小河上建这桥,你就需要计算木材用料,价格等,如果需要别人帮忙,你还要多一些图纸什么的让别人理解你的想法。现在你要在大江上面建桥,你需要有整体的计划,包括各个方面,比如将来可能的收费和利益分配等问题。这里讲3层式,其实是针对“大江上面建桥”来的,对于1米宽的小溪,在

快乐永远的专栏 7455

保姆级教程:QGC地面站Vehicle Setup全模块配置详解(从固件升级到安全设置)

本文提供QGC地面站Vehicle Setup全模块配置的保姆级教程,涵盖从固件升级到安全设置的完整流程。详细解析二次开发环境准备、传感器校准、飞行模式配置等关键步骤,帮助用户快速掌握无人机配置技巧,确保飞行安全与性能优化。

weixin_28726671的博客 386

SelFlow: Self-Supervised Learning of Optical Flow

Pengpeng Liu, Michael Lyu, Irwin King The Chinese University of Hong Kong, § Tencent AI Lab 一篇来自2019年CVPR的自监督光流估计---SelFlow 作者提出一种从无标注数据中学习光流的自监督训练框架。 1)利用Noc-Model 从未遮盖区域,学习可靠的光流信息; 2)利用Noc-Model学习到的可靠的光流信息,去指导OCC-Model 学习被遮挡像素的光流(这些被遮盖的像素,俗称Occlus

weixin_39406427的博客 1062

开源网格划分软件-Gmsh二次开发教程 (4)网格生成与控制​

​本章将深入讲解Gmsh的网格生成技术,包括全局/局部网格控制、边界层生成、自适应细化等,并提供完整的代码示例。

ZQGG的博客 1472

Ubuntu20.04下SRS流媒体服务器的安装与开机自启动优化指南

本文详细介绍了在Ubuntu20.04系统下安装SRS流媒体服务器并优化开机自启动的完整指南。从基础环境准备、服务管理方案对比到systemd自启动深度优化,提供了实用的配置技巧和排查方法,帮助用户快速搭建稳定的流媒体服务环境。特别推荐使用systemd方案实现高效的自启动管理。

weixin_29313239的博客 410

SelFlow: Self-Supervised Learning of Optical Flow-CVPR19

这是CVPR19 paper reading精读任务中的第一篇,Oral Presentation, Best Paper Final List, Top 1%,反正很屌就对了,其实是从他们团队之前AAAI19的一篇文章进化而来的,为了精读这篇CVPR,我读了他们的AAAI19,顺便再go deep读了关于知识蒸馏(knowledge distillation)的三篇稍微古老一点的paper。 NIPS14: Do Deep Nets Really Need to be Deep? 模型压缩 ..

Bruce_0712的博客 1445

VTK的编译和部署,配合c++和visual studio2022,VTK开发环境的配置

在官网选择最新的版本下载之后进行解压,然后再里面创建build目录,方便后面使用cmake进行编译。

dz131lsq的博客 3223

扩散模型性能提升关键:数据扩增策略优化优于复杂自监督机制

扩散模型作为生成式AI的核心技术,通过前向加噪和反向去噪的过程实现高质量图像生成。其训练效果高度依赖数据质量和多样性,而数据扩增技术通过几何变换、颜色调整等手段有效提升训练样本的覆盖范围。在工程实践中,优化数据预处理流程往往比引入复杂的自监督学习机制更能直接提升模型性能,这一发现对降低训练复杂度、提高研发效率具有重要价值。Self-Flow研究表明,针对DiT等新兴架构的数据扩增策略能够显著改善生成质量,为实际应用场景中的模型优化提供了更实用的技术路径。

weixin_30924087的博客 329

[案例四] 智能填写属性工具(支持装配组件还有建模实体属性的批量创建、编辑)

本次案例主要是对上次导出自动导出BOM的一个前处理,要想导出属性,首先的有属性。于是本着学习的态度进行制作,可能有些功能有点别扭(支持装配环境下组件属性的批量填写,支持建模环境下的实体(不包括装配组件实体)——为了减负我把其过滤掉了,一般没人会往装配体里添加进行建模吧,但是不免有奇葩,哈哈哈)。

weixin_47753171的博客 1980

通过理解 sk_buff 深入掌握 Linux 内核自定义协议族的开发实现

在。

数字人生 458

三层式开发中的层次划分讨论[转载]

先举一个曾经在哪本书上看到的例子:现在你想在1米宽的小溪上建一座桥,你会在上面放块木板就完了。如果想在宽一点的小河上建这桥,你就需要计算木材用料,价格等,如果需要别人帮忙,你还要多一些图纸什么的让别人理解你的想法。现在你要在大江上面建桥,你需要有整体的计划,包括各个方面,比如将来可能的收费和利益分配等问题。 这里讲3层式,其实是针对“大江上面建桥”来的,对于1米宽的小溪,在实际中可能一点...

abbkc20864的专栏 120

Open3D——点云构建Delaunay三角网【2026最新版】

点云构建Delaunay三角网

点云侠的博客 8366
上一篇: VB.NET与C#的完美结合
下一篇: 基于MVC模式的Struts框架概述
JavaProgramers
博客等级 码龄22年 660粉丝 304原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值