一起谈.NET技术,走向ASP.NET架构设计——第五章:业务层模式,原则,实践(后篇)

简介:   设计模式  本篇文章主要是接着讨论的在业务层可以采用的或者常用的一些设计模式:  State模式  状态模式允许一个对象在随着它的状态变化而改变它自身的一些行为。  在项目开发的过程中,有一些类,例如一个业务类常常是有自己的一些状态的,而且还存在状态之间的一些转换,有些状态之间是可以进行转换的,有些状态之间是不能转换的。

  设计模式

  本篇文章主要是接着讨论的在业务层可以采用的或者常用的一些设计模式:

  State模式

  状态模式允许一个对象在随着它的状态变化而改变它自身的一些行为。

  在项目开发的过程中,有一些类,例如一个业务类常常是有自己的一些状态的,而且还存在状态之间的一些转换,有些状态之间是可以进行转换的,有些状态之间是不能转换的。就拿一个汽车来举例子,汽车有很多的状态:静止,启动,前进,后退,停车。而且不能由”前进”状态转为“启动”状态。

  很多朋友知道state模式的用法和结构,朋友们应该也清楚在状态之间的转换用swtich.. case的一些弊端。在项目中,很多时候就没有”一定”,”非得”要用state模式来解决类似的问题,即使可以用state模式来解决。如果变化不大,switch.. case就够用了。

  下面还是来首先来看看使用state模式的一些例子。

  还是采用电子商务为背景来举例:每一个订单都是有状态的:New(新的),Shipped(已经发货),Canceled(已取消)。我们知道一个新的订单可以被变为”取消”的状态,也可以成为”已发货”状态。但是订单不能从”已发货”状态,变为”取消”的状态。

  下面就是例子中的类图:

  首先还是创建一个名为:ASPPatterns.Chap5.StatePattern的解决方案,添加一个名为:ASPPattern.Chap5.StatePattern.Model的类库:

  然后添加在Model的类库中添加一个表示状态接口的定义:IOrderState:

   
   
public interface IOrderState
{
bool CanShip(Order Order);
void Ship(Order Order);

bool CanCancel(Order Order);
void Cancel(Order order);

OrderStatus Status {
get ; }
}

  下面来定义个表示订单状态的枚举:

  
  
public enum OrderStatus
{
New
= 0 ,
Shipped
= 1 ,
Canceled
= 2
}

  然后我们来看看,真正要进行状态转化的那个订单类:

  
  
public class Order
{
private IOrderState _orderState;

public Order(IOrderState baseState)
{
_orderState
= baseState;
}

public int Id { get ; set ; }

public string Customer { get ; set ; }

public DateTime OrderedDate { get ; set ; }

public OrderStatus Status()
{
return _orderState.Status;
}

public bool CanCancel()
{
return _orderState.CanCancel( this );
}

public void Cancel()
{
if (CanCancel())
_orderState.Cancel(
this );
}

public bool CanShip()
{
return _orderState.CanShip( this );
}

public void Ship()
{
if (CanShip())
_orderState.Ship(
this );
}

internal void Change(IOrderState OrderState)
{
_orderState
= OrderState;
}
}

  其实状态模式一个最主要的思想就是:把状态之间的转换分离出来,把每一个状态分解为一个个的状态的类,然后这些状态来负责如何在不同的状态之间的转换。也就是说,就本例而言,以前我们会在Order类中写上如下的语句:

  
  
public void ChangeStatus()
{
switch (Status)
{
case OrderStatus.New:
// .... do some things
break ;
case OrderStatus.Shipped:
// .... do some things
break ;

case OrderStatus.Canceled:
// .... do some things
break ;
}
}

  我们知道其实此时就是由Order类来控制了状态之间的转换。其实state模式的就是让那些“状态”变为一个“有思想”的状态类,这些类自己来负责如何以及何时转换到其他的状态,这样Order的“负担”就减轻了。还有一个就是大家常常会”批判”:如何要添加一个新的状态,那么ChangeStatus方法势必会变化,因为这个方法控制了状态之间的转换,如果把状态的转换逻辑分离出去,最好做到添加或者减少状态都不会影响现有的Order就更好了。

  下面的讲述有点直接,希望不熟悉state模式的朋友先“撑下去”J

  1、当创建一个订单的时。候,这个订单的状态肯定就是”New”(新的)。那么我们可能就传入一个表示“New”状态的类:OrderNewStatus:

  new Order(OrderNewState newStatus)

  OrderNewStatus把订单的状态标记为New

  我们知道:订单的状态为New的时候,状态可以向Canceled和Shipped转换,那么OrderNewStatus的定义可能如下:

  
  
public class OrderNewState : IOrderState
{
public bool CanShip(Order Order)
{
return true ;
}

public void Ship(Order Order)
{
Order.Change(
new OrderShippedState());
}

public OrderStatus Status
{
get { return OrderStatus.New; }
}

public bool CanCancel(Order Order)
{
return true ;
}

public void Cancel(Order order)
{
order.Change(
new OrderCanceledState());
}
public new Order(OrderNewState newStatus);
}

  2、当新创建的订单处理到一定的流程的时候,例如要发货了,此时要更新订单的状态,此时我们只要调用Order的ship方法就行了。其实此时我们就是在调用NewOrderStatus类的Ship方法,这个类的ship方法知道怎么做:先判断Order的是否可以向Shipped状态转换(调用CanShip方法),如果可以,那么就new一个OrderShippedStatus状态的类,然后用这个类去替换原来的NewOrderStatus(调用Order类的Change方法),这样,Order的状态就是Shipped了,但是Order完全不用管状态之间是如何变化的。

  
  
public class OrderShippedState : IOrderState
{
public bool CanShip(Order order)
{
return false ;
}

public void Ship(Order order)
{
throw new NotImplementedException( " You can't ship a shipped order! " );
}

public OrderStatus Status
{
get { return OrderStatus.Shipped; }
}

public bool CanCancel(Order Order)
{
return false ;
}

public void Cancel(Order order)
{
throw new NotImplementedException( " You can't ship a shipped order! " );
}

}

  3、Canceled状态也同理,我这里就不在赘述了。

  
  
public class OrderCanceledState : IOrderState
{
public bool CanShip(Order Order)
{
return false ;
}

public void Ship(Order Order)
{
throw new NotImplementedException( " You can't ship a cancelled order! " );
}

public OrderStatus Status
{
get { return OrderStatus.Canceled; }
}

public bool CanCancel(Order Order)
{
return false ;
}

public void Cancel(Order order)
{
throw new NotImplementedException( " You can't ship a cancelled order! " );
}
}

  我们用一个UML图来结束state模式的讲述:

  Strategy模式

  其实策略模式,我这里不打算作太多的讲述,其实这种模式大家到处可见,我们常常在ASP.NET中常常提起的Provider模式,其实就是策略模式的一种实现。

  大家看看结构图,基本上就明白了:

  在上述的图中Context依赖一个IStrategy接口,我们可以决定让Context使用IStrategy的任意的一个实现者:ConcreteStrategyA 或者ConcreteStrategyB。其实就是可以替换不同的实现者。可能大家在数据访问层那块有的体验更加的明显:定义一个IDataProvider,然后实现一个AdoDotNetProvider和一个LinqToSqlProvider。

  架构模式

  下面就来补充一些架构模式的知识,下文主要讲述:Layer Supertype模式(超类模式)

  超类模式就是定义一个基类,然后其他的所有的类都从这个类中继承。对于业务层而言,在超类中可能会定义一些通用的业务规则和验证方法,这样就这些代码被到处分散。也体现了继承的一个好处。

  下面我们就来看一个项目中的例子(电子商务为例),类结构如下:

  大家可以看到,所有的业务类都是从EntityBase继承的。

  
  
public abstract class EntityBase < T >
{
private T _Id;
private bool _idHasBeenSet = false ;
private IList < string > _brokenRules = new List < string > ();

public EntityBase()
{ }

public EntityBase(T Id)
{
this .Id = Id;
}

public T Id
{
get { return _Id; }
set
{
if (_idHasBeenSet)
ThrowExceptionIfOverwritingAnId();

_Id
= value;
_idHasBeenSet
= true ;
}
}

private void ThrowExceptionIfOverwritingAnId()
{
throw new ApplicationException( " You cannot change the id of an entity. " );
}

public bool IsValid()
{
ClearCollectionOfBrokenRules();
CheckForBrokenRules();
return _brokenRules.Count() == 0 ;
}

protected abstract void CheckForBrokenRules();

private void ClearCollectionOfBrokenRules()
{
_brokenRules.Clear();
}

public IEnumerable < string > GetBrokenBusinessRules()
{
return _brokenRules;
}

protected void AddBrokenRule( string brokenRule)
{
_brokenRules.Add(brokenRule);
}
}

  在这个超类中,提供了保存每个业务类唯一标识的逻辑,并且确保这个标识一旦设定就不会被改变。而且这个超类还提供一些简单的验证逻辑。

  我们再来看看如何使用这个超类,下面定义了一个Customer的业务类:

  
  
public class Customer : EntityBase < long >
{
public Customer() { }

public Customer( long Id)
:
base (Id)
{ }

public string FirstName { get ; set ; }
public string LastName { get ; set ; }

protected override void CheckForBrokenRules()
{
if (String.IsNullOrEmpty(FirstName))
base .AddBrokenRule( " You must supply a first name. " );

if (String.IsNullOrEmpty(LastName))
base .AddBrokenRule( " You must supply a last name. " );
}
}

  在这个类中,我们定义了唯一标识的类型:long,而且还定义了一些业务规则:FirstName, LastName不为空。至于如何调用这些验证规则,在超类中已经实现了,此时业务类就“轻松”了很多—起码不用再次写那些相类似的代码了,实现了一定程度上的代码重用。

  今天就讲到这里了,不正确之处,还望朋友们指出,见谅!

  多谢支持!

   
目录
相关文章
|
3月前
|
存储 缓存 安全
某鱼电商接口架构深度剖析:从稳定性到高性能的技术密码
某鱼电商接口架构揭秘:分层解耦、安全加固、性能优化三维设计,实现200ms内响应、故障率低于0.1%。详解三层架构、多引擎存储、异步发布、WebSocket通信与全链路防护,助力开发者突破电商接口“三难”困境。
|
3月前
|
人工智能 自然语言处理 安全
AI助教系统:基于大模型与智能体架构的新一代教育技术引擎
AI助教系统融合大语言模型、教育知识图谱、多模态交互与智能体架构,实现精准学情诊断、个性化辅导与主动教学。支持图文语音输入,本地化部署保障隐私,重构“教、学、评、辅”全链路,推动因材施教落地,助力教育数字化转型。(238字)
|
3月前
|
Java Linux 虚拟化
【Docker】(1)Docker的概述与架构,手把手带你安装Docker,云原生路上不可缺少的一门技术!
1. Docker简介 1.1 Docker是什么 为什么docker会出现? 假定您在开发一款平台项目,您的开发环境具有特定的配置。其他开发人员身处的环境配置也各有不同。 您正在开发的应用依赖于您当前的配置且还要依赖于某些配置文件。 您的企业还拥有标准化的测试和生产环境,且具有自身的配置和一系列支持文件。 **要求:**希望尽可能多在本地模拟这些环境而不产生重新创建服务器环境的开销 问题: 要如何确保应用能够在这些环境中运行和通过质量检测? 在部署过程中不出现令人头疼的版本、配置问题 无需重新编写代码和进行故障修复
395 2
|
3月前
|
存储 人工智能 搜索推荐
拔俗AI助教系统:基于大模型与智能体架构的新一代教育技术引擎
AI助教融合大语言模型、教育知识图谱、多模态感知与智能体技术,重构“教、学、评、辅”全链路。通过微调LLM、精准诊断错因、多模态交互与自主任务规划,实现个性化教学。轻量化部署与隐私保护设计保障落地安全,未来将向情感感知与教育深度协同演进。(238字)
|
3月前
|
Cloud Native Serverless API
微服务架构实战指南:从单体应用到云原生的蜕变之路
🌟蒋星熠Jaxonic,代码为舟的星际旅人。深耕微服务架构,擅以DDD拆分服务、构建高可用通信与治理体系。分享从单体到云原生的实战经验,探索技术演进的无限可能。
微服务架构实战指南:从单体应用到云原生的蜕变之路
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
6月前
|
缓存 Cloud Native Java
Java 面试微服务架构与云原生技术实操内容及核心考点梳理 Java 面试
本内容涵盖Java面试核心技术实操,包括微服务架构(Spring Cloud Alibaba)、响应式编程(WebFlux)、容器化(Docker+K8s)、函数式编程、多级缓存、分库分表、链路追踪(Skywalking)等大厂高频考点,助你系统提升面试能力。
317 0
|
Cloud Native Devops 云计算
云计算的未来:云原生架构与微服务的革命####
【10月更文挑战第21天】 随着企业数字化转型的加速,云原生技术正迅速成为IT行业的新宠。本文深入探讨了云原生架构的核心理念、关键技术如容器化和微服务的优势,以及如何通过这些技术实现高效、灵活且可扩展的现代应用开发。我们将揭示云原生如何重塑软件开发流程,提升业务敏捷性,并探索其对企业IT架构的深远影响。 ####
365 3