1:项目场景

  在设计数据表的时候有时候为了将来统计或查询的方便,我们会冗余一些字段。如有三张数据表,学校信息表、班级动态表、班级信息表。

  班级动态由学校老师所发,可以进行评论点赞等操作,为了提升这种非结构化数据的访问效率,存储于Mongodb中,冗余了学校名称字段,假设班级表也冗余了学校名称字段。而冗余字段的存在可能会带来数据不一致问题。这边需要保持修改学校名称时,其他相关的表中学校名称字段保持一致,先看根据业务逻辑最直接的写法。

1.1:先定义类

   /// <summary>
/// 学校信息表
/// </summary>
public class School
{
public string RowGuid { get; set; }
public string SchoolName { get; set; }
} /// <summary>
/// 班级动态(假设存储于Mongodb,为按学校名称模糊查询时方便,冗余学校名称字段)
/// </summary>
public class PersonDynamic
{
public string RowGuid { get; set; }
public string Title { get; set; }
public string MainContent { get; set; }
/// <summary>
/// 发布人标识
/// </summary>
public string TeacherGuid { get; set; }
/// <summary>
/// 冗余发布人所在学校Guid
/// </summary>
public string SchoolGuid { get; set; }
/// <summary>
/// 冗余发布人所在学校名称
/// </summary>
public string SchoolName { get; set; }
} /// <summary>
/// 班级信息 假设冗余学校名称
/// </summary>
public class Class
{
public string RowGuid { get; set; }
public string ClassName { get; set; }
public string SchoolGuid { get; set; }
public string SchoolName { get; set; }
}

1.2对应逻辑层设计

public class BlClass
{
//更新班级表中学校名称数据
public void UpdateClass(School school)
{
//string sql = string.Format("update ClassInfo set SchoolName ='{0}' where SchoolGuid ='{1}'", school.SchoolName, school.RowGuid);
Console.WriteLine("完成修改班级表的学校名称。");
}
}
   public class BlPersonDynamic
{
//更新班级动态数据表中学校名称
public void UpdatePersonDynamic(School school)
{
//MongoDBHelper.Update(……)
Console.WriteLine("完成修改班级动态表的学校名称。");
}
}
public class BlSchool
{
public void UpdateSchool(School school)
{
//修改学校名称逻辑
// string sql = string.Format("update Schoolinfo set SchoolName ='{0}' where RowGuid ='{1}'", school.SchoolName, school.RowGuid);
Console.WriteLine("完成修改学校信息表的学校名称。");
new BlPersonDynamic().UpdatePersonDynamic(school);
new BlClass().UpdateClass(school); }
}

1.3:需求扩展:

  可以预见到,之后还会增加教师文章,学校新闻等等内容,里面仍然可能冗余学校名称字段,那么更新学校名称的逻辑则时常需要修改,违反了开闭原则。其他类中的学校名称字段依赖于学校表的学校名称,当学校表中学校名称改变时,其他表学校名称也需要同步改变,由此想到了一种开发模式,观察者模式。

2:使用观察者模式改造

2.1百度百科中的定义

  观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

2.2类图

  

2.3 C#使用委托事件方式实现观察者模式

  此处改造先不考虑抽象观察者 和 抽象主题,学校作为通知者,班级和班级动态作为观察者角色,这样的好处是不影响现有的观察者逻辑,调整后的逻辑层。

//具体观察者1
public class BlClass
{
public void UpdateClass(School school)
{
// string sql = string.Format("update ClassInfo set SchoolName ='{0}' where SchoolGuid ='{1}'", school.SchoolName, school.RowGuid);
Console.WriteLine("完成修改班级表的学校名称。");
}
}
 //具体观察者2
public class BlPersonDynamic
{
//更新班级动态数据表中学校名称
public void UpdatePersonDynamic(School school)
{
//MongoDBHelper.Update(……)
Console.WriteLine("完成修改班级动态表的学校名称。");
}
}
//声明一个委托
public delegate void UpdateSchoolEvent(School school); //通知者
public class BlSchool
{
//声明一个事件
public event UpdateSchoolEvent updateSchoolEvent;
public void UpdateSchool(School school)
{
//首先更新学校表中名称
//string sql = string.Format("update Schoolinfo set SchoolName ='{0}' where RowGuid ='{1}'", school.SchoolName, school.RowGuid);
Console.WriteLine("完成修改学校表数据!");
//修改学校名称后发起通知,触发事件
this.Notice(school);
}
public void Notice(School school)
{
//如果事件非空则调用
updateSchoolEvent?.Invoke(school);
}
}

  这样调整后则完成了学校 与 班级、动态之间的耦合度,新增其他需要更新的地方也不需要修改学校逻辑层。只需要在使用的地方注册一下事件,如下面的模拟调用:

//修改后的实体类信息
School school = new School();
school.RowGuid = Guid.NewGuid().ToString();
school.SchoolName = "第一中学"; //注册修改学校名称事件
BlSchool blSchool = new BlSchool();
blSchool.updateSchoolEvent += new BlPersonDynamic().UpdatePersonDynamic;
blSchool.updateSchoolEvent += new BlClass().UpdateClass; //更新学校名称
blSchool.UpdateSchool(school);
Console.ReadKey();

2.4思考一

  当做功能扩展的时候,原先的写法是在学校逻辑层调整修改学校的逻辑,而使用观察者模式之后仍然需要注册事件的地方增加注册事件,都是需要修改是否有区别?个人理解首先是解除了类之间的耦合度,其次我觉得开闭原则对修改关闭、对扩展开放,并不是意味着功能拓展不需要改变任何以前的代码,而是拓展后改变需要花费代价的大小,如同一些配置参数的使用,也是为了最小的代价完成功能的修改或拓展。而此处学校业务逻辑层如果已经是封装好的主程序逻辑,那么修改需要花费较大的代价。

2.5思考二

  对于观察者模式的抽象主题、和抽象观察者的使用。比如在原先基础上增加了学校新闻的功能,此时并不知道需要写下面这个 和以前相同参数的方法。

 //具体观察者3
public class BlSchoolNews
{
//更新班级动态数据表中学校名称
public void UpdateSchoolNews(School school)
{
//MongoDBHelper.Update(……)
Console.WriteLine("完成修改学校新闻表的学校名称。");
}
}

  那么这里则可以对具体的观察者进行抽象,对于对修改学校感兴趣的类,实现这个抽象的接口。抽象后如下

/// <summary>
/// 抽象一个更新学校接口
/// </summary>
public interface IUpdateSchool
{
void AfterUpdateSchool(School school);
} //具体观察者1
public class BlClass : IUpdateSchool
{
public void AfterUpdateSchool(School school)
{
this.UpdateClass(school);
} private void UpdateClass(School school)
{
// string sql = string.Format("update ClassInfo set SchoolName ='{0}' where SchoolGuid ='{1}'", school.SchoolName, school.RowGuid);
Console.WriteLine("完成修改班级表的学校名称。");
}
}
//具体观察者2
public class BlPersonDynamic : IUpdateSchool
{
public void AfterUpdateSchool(School school)
{
this.UpdatePersonDynamic(school);
}
//更新班级动态数据表中学校名称
private void UpdatePersonDynamic(School school)
{
//MongoDBHelper.Update(……)
Console.WriteLine("完成修改班级动态表的学校名称。");
}
}
//具体观察者3
public class BlSchoolNews : IUpdateSchool
{
public void AfterUpdateSchool(School school)
{
this.UpdateSchoolNews(school);
}
//更新班级动态数据表中学校名称
private void UpdateSchoolNews(School school)
{
//MongoDBHelper.Update(……)
Console.WriteLine("完成修改学校新闻表的学校名称。");
}
}

  模拟调用

 //修改后的实体类信息
School school = new School();
school.RowGuid = Guid.NewGuid().ToString();
school.SchoolName = "第一中学"; //注册修改学校名称事件
BlSchool blSchool = new BlSchool();
blSchool.updateSchoolEvent += new BlPersonDynamic().AfterUpdateSchool;
blSchool.updateSchoolEvent += new BlClass().AfterUpdateSchool;
blSchool.updateSchoolEvent += new BlSchoolNews().AfterUpdateSchool;
//更新学校名称
blSchool.UpdateSchool(school);
Console.ReadKey();

  

C#观察者模式的应用与思考的更多相关文章

  1. 深入浅出写一个多级异步回调从基础到Promise实现的Demo

    今天一时兴起,写了一个渐进升级的异步调用demo,记录一下. 1. 最基础的同步调用 //需求:f2在f1之后执行,且依赖f1的返回值.如下: function f1(){ var s="1 ...

  2. [python实现设计模式]-4.观察者模式-吃食啦!

    观察者模式是一个非常重要的设计模式. 我们先从一个故事引入. 工作日的每天5点左右,大燕同学都会给大家订饭. 然后7点左右,饭来了. 于是燕哥大吼一声,“饭来啦!”,5点钟定过饭的同学就会纷纷涌入餐厅 ...

  3. IOS设计模式-观察者模式

    前言:23种软件设计模式中的观察者模式,也是在软件开发中,挺常用的一种设计模式.而在苹果开发中,苹果Cocoa框架已经给我们实现了这个设 计模式,那就是通知和KVO(Key-Value Observi ...

  4. C#设计模式(17)——观察者模式(Observer Pattern)

    一.引言 在现实生活中,处处可见观察者模式,例如,微信中的订阅号,订阅博客和QQ微博中关注好友,这些都属于观察者模式的应用.在这一章将分享我对观察者模式的理解,废话不多说了,直接进入今天的主题. 二. ...

  5. 那些年做过的 .NET Web 项目和 iOS 之路的一些思考

    从2010年3月份出来工作到2015年初,做过的大大小小的 .NET Web 项目如下: (1)售楼系统产品    「Role: Team Member」 (2)中弘合同管理系统    「Role: ...

  6. php模式设计之 观察者模式

    这是我写的<php模式设计>的第五篇.前面的四篇在不断学习不断加深认识,到了今天再看观察者模式,觉得非常容易理解.这也许就是我们积少成多的结果吧.希望还是能够不断进步. 开篇还是从名字说起 ...

  7. 设计模式13---设计模式之观察者模式(Observer)(行为型)

    1.场景模式抽象 订阅报纸的过程,如果报纸来了的时间不确定,那么订报纸的人如何知道呢?可以抽象为:当一个对象的状态发生改变的时候,如何让依赖他的所有对象得到通知,并进行相应的处理呢?生活中最常见的例子 ...

  8. 理解java设计模式之观察者模式

    在生活实际中,我们经常会遇到关注一个事物数据变化的情况,例如生活中的温度记录仪,当温度变化时,我们观察它温度变化的曲线,温度记录日志等.对于这一类问题,很接近java设计模式里面的“观察者模式”,它适 ...

  9. 读headFirst设计模式 - 观察者模式

    上次学习了策略模式,这次来学习观察者模式.这次先把书上的例子学习一下,然后再自己写一个例子,看是否能做到举一反三(或者说触类旁通),不过要想真正的掌握还要多多思考和练习. 学习书上的例子 现在我们有一 ...

随机推荐

  1. 欢迎使用CSDN-markdown编辑器a

    这里写自定义目录标题 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一 ...

  2. 操作系统(Operating System,OS)

    操作系统(Operating System,OS) 是配置在计算机硬件上的第一层软件,是对计算机硬件系统的首次扩充,是一个计算机系统最基础,也是最重要的系统软件. 操作系统的作用 1 实现对计算机资源 ...

  3. 盗墓笔记—阿里旺旺ActiveX控件imageMan.dll栈溢出漏洞研究

    本文作者:i春秋作家——cq5f7a075d 也许现在还研究Activex就是挖坟,但是呢,笔者是摸金校尉,挖坟,呸!盗墓是笔者的本职工作. 额,不扯了,本次研究的是阿里旺旺ActiveX控件imag ...

  4. win10无法访问samba共享

    地址: https://blog.csdn.net/xiaohuixing16134/article/details/79601064?utm_source=blogxgwz1 问题描述:配置好sam ...

  5. Centos7永久修改IP地址

    Centos7永久修改IP地址 永久修改IP地址,即为设置静态的IP地址. 一.修改IP地址前需要准备的工作 1.虚拟机需要使用桥接的网络模式 虚拟机关机状态下,点击"编辑虚拟机设置&quo ...

  6. 扩展中国剩余定理(扩展CRT)详解

    今天在$xsy$上翻题翻到了一道扩展CRT的题,就顺便重温了下(扩展CRT模板也在里面) 中国剩余定理是用于求一个最小的$x$,满足$x\equiv c_i \pmod{m_i}$. 正常的$CRT$ ...

  7. XCode9的新变化

    XCode9已经随着ios11的发布发布了,那么在这个XCode9版本中有哪些变化呢? 1 折叠代码 焦点在方法的实现体的方法名上,按comman键,则整个函数会被框住.用来标志这个方法的起点和终点 ...

  8. POJ 1157

    #include<iostream> //成大才子---经典代码~ #include<stdio.h> #include<algorithm> #define MA ...

  9. Visual Studio 2015中使用gdb远程调试linux程序

    VS的debug功能非常强大,相比而言linux上的图形化调试一直不是很好用. 如果可以使用VS来调试linux程序,应该是一件比较愉快的事情. 这在2015中变得可能,因为从2015开始VS支持An ...

  10. 解决Nginx 504 Gateway Time-out问题

    解决方案:在http里设置FastCGI相关参数,如: worker_processes 1; events { worker_connections 1024; } http { include m ...