当前位置: 首页 > 编程日记 > 正文

从设计原则谈软件开发(二)

最近一直在一个培训公司做着极为无聊的培训,所以一直都没有时间上网。今天突然发现这里可以上无线,嘿嘿,就上来继续把这个文章完成。

上次说到了设计原则中的单一职责原则,今天时间比较紧,我就继续往下写,也不知道能写几个。

现在来说一下设计模式的核心,开放封闭原则(OCP原则)。开放封闭原则我想每一个人都可以从字面上很容易地理解他的意思,就是说对扩展开放,对修改封闭。一个优秀的软件是可以无限扩展的,而且是不需要修改类的内部结构的(当然这是指的理想状况,实际上,无论设计多么优异的软件,一旦扩展,总是要对类内部进行修改的)。

上次我记得我说过,设计模式,也是OO的目标,无非是两个,可重用和可扩展。我们来从这两个方面来分析OCP,我们先说可扩展,这个我想我不用多说了,都说过对扩展开放的,当然是可扩展了。可重用等我先举个例子再来分析下这个。

在这个,我举个我前两天做的一个小型计算器。我们先来分析一下这个小型计算器,我把一个小型计算器的按钮抽象为以下几个功能:数字键,二元运算符,一元运算符,修饰符(比如说小数点),等于号。然后我把这几个功能分别封装成一个自定义控件。现在来说下二元运算符,代码如下:

ContractedBlock.gifExpandedBlockStart.gifCode
 1    public partial class ButtonOperateTwo : UserControl
 2ExpandedBlockStart.gifContractedBlock.gif    {
 3        private TextBox textBoxResult = null;
 4        public ButtonOperateTwo()
 5ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 6            InitializeComponent();
 7        }

 8        public ButtonOperateTwo(string text, TextBox textBoxResult)
 9ExpandedSubBlockStart.gifContractedSubBlock.gif        {
10            InitializeComponent();
11            this.buttonOperate.Text = text;
12            this.textBoxResult = textBoxResult;
13        }

14
15        private void buttonOperate_Click(object sender, EventArgs e)
16ExpandedSubBlockStart.gifContractedSubBlock.gif        {
17            SaveNumber1(this.textBoxResult.Text);
18            this.textBoxResult.Text = "0";
19            SaveOperate(this.buttonOperate.Text);
20        }

21
22        private void SaveNumber1(string num1)
23ExpandedSubBlockStart.gifContractedSubBlock.gif        {
24            Number.Number1 = this.textBoxResult.Text;
25        }

26        private void SaveOperate(string operate)
27ExpandedSubBlockStart.gifContractedSubBlock.gif        {
28            Number.Operate = operate;
29        }

30    }

ContractedBlock.gifExpandedBlockStart.gifCode
1    public struct Number
2ExpandedBlockStart.gifContractedBlock.gif    {
3        public static string Number1 = "0";
4        public static string Number2 = "0";
5        public static string Operate = "+";
6    }

在这里,我来简单地说下我这段程序的思路。我之前没有做过任何Winform程序,没有找到缓存,因此我声明了一个结构体来存储所需要的数字和操作符。然后当点击二元运算符后,我就把textBoxResult的Text传入到Number1中,然后同时也把操作符来暂存到结构体中。这样,以后无论有什么二元运算符,我们都不需要再写那么多重复的代码,而只需要简单的调用这个二元运算符就可以了,而不需要任何修改。

因此,我们很常用的自定义控件,就是开放封闭原则的最好体现。

基本上所有设计模式的目的都是开放封闭。在这里,我来简单地提下一个很好地体现了开放封闭的设计模式——工厂模式。

工厂模式是创建者模式的一种,用于解决对象的创建问题。我的这个计算器应用的就是工厂模式。

我这里不大方便画图,就用语言来描述一下吧。

我创建两个类库,分别为运算类库和工厂类库。在运算类库中有一个基类OperateBase,在他的下面有两个子类分别为一元运算子类和二元运算子类。而这个子类下又分别有着具体的运算子类。在工厂类库中有两个基类,分别是二元运算工厂类和一元运算工厂类。而每个基类下又有着具体的运算工厂类,分别用于返回运算类。我们来简单地看一些示例代码:

ContractedBlock.gifExpandedBlockStart.gifCode
 1    public abstract class OperateBase //运算基类
 2ExpandedBlockStart.gifContractedBlock.gif    {
 3        public abstract string GetResult();
 4    }

 5    public abstract class OperateOne:OperateBase   //一元运算基类
 6ExpandedBlockStart.gifContractedBlock.gif    {
 7        public double Number1
 8ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 9            get;
10            set;
11        }

12    }

13    public class OperateSqrt:OperateOne   //开方运算
14ExpandedBlockStart.gifContractedBlock.gif    {
15        public override string GetResult()
16ExpandedSubBlockStart.gifContractedSubBlock.gif        {
17            double result;
18            result = Math.Sqrt(Number1);
19            return result.ToString();
20        }

21    }

22    public abstract class OperateFatoryOne //一元运算工厂基类
23ExpandedBlockStart.gifContractedBlock.gif    {
24        protected OperateOne thisOperate = null;
25        public abstract OperateOne GetOperate();
26    }

27    public class OperateFactorySqrt : OperateFatoryOne  //开方运算工厂类
28ExpandedBlockStart.gifContractedBlock.gif    {
29        public override OperateOne GetOperate()
30ExpandedSubBlockStart.gifContractedSubBlock.gif        {
31            return new OperateSqrt();
32        }

33    }

34    private string ReturnResult()  //客户端调用方法
35ExpandedBlockStart.gifContractedBlock.gif        {
36            try
37ExpandedSubBlockStart.gifContractedSubBlock.gif            {
38                OperateFactory.OperateFatoryOne thisOperateFactory = null;
39                switch (this.button1.Text)
40ExpandedSubBlockStart.gifContractedSubBlock.gif                {
41                    case "+/-":
42                        thisOperateFactory = new OperateFactory.OperateFactoryReverse();
43                        break;
44                    case "sqrt":
45                        thisOperateFactory = new OperateFactory.OperateFactorySqrt();
46                        break;
47                    case "1/x":
48                        thisOperateFactory = new OperateFactory.OperateFactoryCountDown();
49                        break;
50                    case "%":
51                        thisOperateFactory = new OperateFactory.OperateFactoryPercent();
52                        break;
53                }

54                OperatingSystem.Operate.OperateOne thisOperate = thisOperateFactory.GetOperate();
55                thisOperate.Number1 = Convert.ToDouble(this.thisTextBox.Text);
56
57                string result = thisOperate.GetResult();
58                return result;
59            }

60            catch 
61ExpandedSubBlockStart.gifContractedSubBlock.gif            {
62                string result = "您的输入有误";
63                return result;
64            }

65                
66        }

67
68

于是,我们就可以自由地添加一元运算符了,当添加时,我们只需要添加一个运算子类,添加一个工厂子类,然后在客户端的switch的case中添加一个条件。当然,这里就是我说的,不存在完全的开放封闭,无论设计多么优异的软件。即使在这里用抽象工厂+反射,也仍然需要加以修改,我没那样设计的原因是因为那样的设计对效率实在有点.....

最后,对以上的文字做个总结。

开放封闭原则是整个设计模式的核心,依我的理解,所有的设计模式,包括所有的设计原则都是围绕着OCP展开的。一个优秀的软件设计师可以忘记所有的设计模式,甚至都可以忘记所有的设计原则,但是开放封闭原则必须永记心中。

好了,就写到这。然后说个昨天开《建筑的永恒之道》,上面有这样一句话,什么才能成就建筑的永恒之道,学会方法,然后忘掉他。

相关文章:

Npm环境依赖重置

需要彻底删除node_modules 然后npm install 如果无法删除node_modules文件,可以试试这个: 安装RimRaf: npm install rimraf -g 并在项目文件夹中删除node_modules文件夹: rimraf node_modules 然后你可以去npm install转载于:http…

MySQL的information_schema

在一次清空一张比较大的表时(在清空前占用400多兆),发现该表中记录为0条但是空间并没有被释放,采用下面方式可查看占用情况 -- 查询各个数据库占用磁盘的情况 select TABLE_SCHEMA, concat(truncate(sum(data_length)/1024/1024,2…

编写spring应用

测试类自动注入失败&#xff1a;RunWith(SpringRunner.class)详解 CtrlAltDelete键&#xff0c;打开任务管理器&#xff0c;结束占据8080端口的Tomcat进程。 HomeController.java <!DOCTYPE html> <html xmlns"http://www.w3.org/1999/xhtml"xmlns:th&quo…

[导入]Learning.ASP.NET 2.0.with.AJAX.pdf(14.14 MB)

ASP.NET 2.0的AJAX无疑是最快&#xff0c;最有效&#xff0c;最可靠和最佳的方式支持创建交互式Web应用程序上市。结合开发工具&#xff0c;可以从Microsoft &#xff0c;免费和商业&#xff0c;这是难以置信轻松地创建网站&#xff0c;看看伟大的表现良好。最重要的是&#xf…

c# IO线程 打造 定时打开指定程序

用IO以及线程轻松实现 定时器 &#xff0c;在指定的时间打开指定的程序&#xff1a;&#xff09; 首先是如何实现定时&#xff1f;这可以单独的用个线程&#xff0c;在时间到的时候打开程序 然后是如何打开程序 &#xff0c;用Process.Start就可以了 最后就是如何把程序列表保存…

Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

Memcached Memcached 是一个高性能的分布式内存对象缓存系统&#xff0c;用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数&#xff0c;从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程&#xf…

jQuery中的常用内容总结(一)

jQuery中的常用内容总结(一) 前言 不好意思(✿◠‿◠)&#xff0c;由于回家看病以及处理一些其它事情耽搁了&#xff0c;不然这篇博客本该上上周或者上周写的&#xff1b;同时闲谈几句&#xff1a;在这里建议各位开发的童鞋&#xff0c;如果有疾病尽快治疗&#xff0c;不要拖&a…

你需要眼光和资格

机上遇到一男人&#xff0c;操北京口音&#xff0c;三十二三&#xff0c;婚否不详&#xff0c;容貌体面。 优势&#xff1a;技术好&#xff0c;聪明&#xff0c;没坏心&#xff0c;乐观 劣势&#xff1a;有点懒&#xff0c;自傲&#xff0c;责任心与意志力指数一般 其所谓“恰当…

嵌入式系统基础了解

1.一个启动 .s文件&#xff08;start.s&#xff09;&#xff0c;至少需要包含三个段: ;//堆栈段 ; //中断向量表 ; //代码段 参考代码&#xff1a; stack_size EQU 0x200 ;…

BFD与IGP快速收敛应用测试

cqmmx&#xff0c;2008-9-10 1、背景介绍 目前对网络稳定性影响较大的一般是链路中断、节点失效等故障&#xff0c;而常规的慢Hello机制检测耗时较长&#xff0c;且常用IGP&#xff08;ISIS和OSPF&#xff09;在默认配置情况下&#xff0c;收敛速度很慢&#xff0c;一般需要几十…

rsa证书ssh登陆服务器

好久不用&#xff0c;又生疏了。 今晚实操了一下&#xff0c;作一个记录。 使用rsa的密钥对登陆linux服务器&#xff0c;主要是为了安全。 这种证书级别的登陆&#xff0c;比最复杂的root用户名和帐号的安全性都要高一个等级。 至少服务器不会被暴破(暴力破解)。 ~~~~~~~~~~~~~…

简单数据结构(队列 栈 树 堆 )

基础知识 基本概念 程序 算法 数据结构数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。 常见…

cannot access a closed file

用上传控件上传文件时&#xff0c;当执行SaveAs()时出错&#xff0c;异常为cannot access a closed file&#xff1b; 当传小文件没有异常&#xff0c;当超过80k时就出上述异常&#xff0c;后来发现要将Web.config里增加 <!--设置上传附近的大小--> <httpRuntime …

实验四-常用图像增强方法

1、采用二维中值滤波函数medfilt2 对受椒盐噪声干扰的图像滤波&#xff0c;窗口分别采用3*3,5*5,7*7 i imread(D:\study\third_down\ImageProcessing\work\work_one\flower.jpg); I rgb2gray(i); J imnoise(I,salt & pepper,0.04); K1 medfilt2(J,[3 3]);%对矩阵I进行…

商贸通服装鞋帽版客户端无法连接服务器的问题(自己遇到的,已解决)

今天给一客户装“商贸通服装鞋帽版”&#xff0c;客户机是xp&#xff0c;服务器是win2003,装好后在连接服务器是总是报“无法连接服务器”之类的错&#xff0c;但是客户机和服务器双向都可以ping的通&#xff0c;而且双方的防火墙都已关闭&#xff0c;没有第三方防火墙&#xf…

【转】Visual C#创建和使用ActiveX组件

开发基于.net平台上的程序员是很难从本质上把Visual C#和ActiveX组件联起来&#xff0c;虽然在使用Visual C#开发应用程序时&#xff0c;有时为了快速开发或者由于.Net Framework SDK的不完整&#xff0c;还需要借助ActiveX。但即使如此&#xff0c;也很难把二者联系起来。其中…

Why Sleeping May Be More Important Than Studying

Why Sleeping May Be More Important Than Studying转载于:https://www.cnblogs.com/Lamfai/p/10441451.html

测试开发板与主机之间通过串口收发数据(uart.c/uart.h )

usart.c: #include "usart.h"// U1_TX: PA9 // U1_RX: PA10 void usart_init(void) {//1. GPIO口的配置RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); GPIO_InitTypeDef p;p.GPIO_Mode GPIO_Mode_AF;p.GPIO_Pin GPIO_Pin_9 | GPIO_Pin_10;p.GPIO_PuPd G…

卷积神经网络--CNN

1.人工神经网络 神经网络由大量的节点&#xff08;或称“神经元”、“单元”&#xff09;和相互连接而成。每个神经元接受输入的线性组合&#xff0c;进行非线性变换&#xff08;亦称激活函数activation function&#xff09;后输出。每两个节点之间的连接代表加权值&#xff0…

基于WinCE的I2C驱动程序设计

http://www.mcu123.com/news/Article/rtos/WinCE/200607/88.html 引言 随着以计算机技术、通信技术和软件技术为核心的信息技术的迅速发展&#xff0c;嵌入式系统在各行业得到了广泛的应用&#xff0c;极大地推动了行业的渗透性应用。嵌入式系统是“以应用为中心、以计算机技…

poj2965-poj2965-The Pilots Brothers' refrigerator

方法同poj1753&#xff0c;但用在这题就TLE了&#xff0c;以下是TLE版本&#xff1a; Code1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#define MAXSTATE 65536 5#define MAXSIZE 16 6#define ALLOPEN 0 7 8//队列结构体 9type…

sysctl -p详解

个人一般sysctl -p 或sysctl -a比较多使用 sysctl配置与显示在/proc/sys目录中的内核参数&#xff0e;可以用sysctl来设置或重新设置联网功能&#xff0c;如IP转发、IP碎片去除以及源路由检查等。用户只需要编辑/etc/sysctl.conf文件&#xff0c;即可手工或自动执行由sysctl控…

定制简单的Linux系统

定制简单的Linux系统 制作思路&#xff1a; 新加一块硬盘&#xff0c;设置两个分区&#xff0c;一个存/boot&#xff0c;一个存/&#xff0c;创建文件系统并格式化。要注意&#xff0c;现在我们家的硬盘是要可以拔下来安装到其他机器上使用的&#xff0c;否则就没有意义了。试…

UCOS同步与互斥

代码为老师教授。 /* ********************************************************************************************************* * EXAMPLE CODE * * (c) Copyright 2013; Micrium, Inc.; We…

Spring学习八

1&#xff1a; Tomcat容器四个等级&#xff1f; Container&#xff0c; Engine&#xff0c; Servlet容器&#xff0c; Context 真正管理Servlet的容器是Context容器&#xff1a;一个context对应一个web工程。 <Context path"/projectOne " docBase"D:\proje…

作业六:图像编码相关概念

7.1&#xff0e;信息量&#xff1a;信息源发出的所有消息中该消息出现概率的倒数的对数。信息熵&#xff1a;对信息源X的各符号的自信息量取统计平均。 7.6如图所示&#xff1a;哈夫曼编码最终结果为&#xff1a;X11,X201,X3000,X4001。编码效率为95%。 7.8根据公式&#xff…

linux命令find命令详解

find 查找文件 find 哪里 什么类型 什么名字 -maxdepth 最大的深度 查找目录的最大深度 find -maxdepth 1 -type d -type 找什么类型的 f file 文件 d directory 目录 -name 什么名字 -mtime 根据修改时间找出对应的文件 7 7天前 -7 7天后 find命令一般与 |xargs 一起…

一次次小进步,从毕业开始,你到现在飞跃了几次了,程序人生也不容易?

01. 会写最简单的程序&#xff0c;能编译通过了&#xff0c;是一次飞跃。02. 会写C/S程序了&#xff0c;能用那些常用的控件&#xff0c;对属性事件有了解了&#xff0c;会用了&#xff0c;是一次飞跃。03. 会写B/S程序了&#xff0c;也是一次飞跃。04. 你彻底理解了分层的理念…

什么是JAVA内容仓库(Java Content Repository)(3)

开发我们的例子程序 jackrabbit已经配置好了&#xff0c;现在让我们来创建我们的示例程序。这个例子程序将调用JCR-170 API。很显然&#xff0c;我们需要做两件事情&#xff1a;一个是作为后台的对数据进行增删改查&#xff08;持久层&#xff09;&#xff0c;另一个是开发相对…

Cygwin-添加到右键菜单脚本--一键安装、卸载

平时习惯用一些linux命令来完成工作&#xff0c;在Windows上有cygwin和gitbash两个选择。这两个我都装了。 相对来说cygwin支持的功能更多一些&#xff0c;但是它没有默认绑定到右键菜单。为此&#xff0c;我想到用万能的注册表解决这个事情。网上搜索了一下&#xff0c;把我眼…