设计模式
序言-四大发明之活字印刷——面向对象思想的胜利
四大发明之活字印刷——面向对象思想的胜利
以曹操对酒当歌,人生几何的典故,引出活字印刷术。
优点:
- 要改,只需更改要改之字,此为可维护
- 这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用
- 此诗若要加字,只需另刻字加入即可,这是可扩展
- 字的排列其实有可能是竖有可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。
对于软件开发来说,客户会时不时的改变需求,更改最初的想法,其实客户的要求并不过分,对于已经完成的程序代码,确实需要大量的改动,原因就是:原先所写的程序,不容易维护,灵活性差,不容易扩展,更谈不上复用,因此面对需求变化,加班加点,对程序动大手术的那种无耐也就非常正常的事了。
学习了面向对象分析设计的编程思想,开始考虑通过封装、继承、多态把程序的耦合性降低(传统印刷术的
问题就在于所有的字都刻在同一版面上造成耦合度太高所制)
开始用设计模式使得程序更加的灵活,容易修改,并且易于复用
第一章 面试受挫——代码无错就是好?
利用小菜毕业找工作手写题目的例子:
“请用C++、Java、C#或VB.NET任意一种面向对象语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。”
class Program { static void Main(string[] args) { Console.Write("请输入数字A:"); string A = Console.ReadLine(); Console.Write("请选择运算符号(+、-、*、/):"); string B = Console.ReadLine(); Console.Write("请输入数字B:"); string C = Console.ReadLine(); string D = ""; if (B == "+") D = Convert.ToString(Convert.ToDouble(A) + Convert.ToDouble(C)); if (B == "-") D = Convert.ToString(Convert.ToDouble(A) - Convert.ToDouble(C)); if (B == "*") D = Convert.ToString(Convert.ToDouble(A) * Convert.ToDouble(C)); if (O == "/") D = Convert.ToString(Convert.ToDouble(A) / Convert.ToDouble(C)); Console.WriteLine("结果是:" + D); } }
第二章 代码规范、重构
需要改进的地方:
- 变量命名:变量不带有任何具体的含义
- 判断分支:每个条件都要判断
- 数据输入有效性判断:如果用户输入的是字符符号而不是数字,如果除数时,用户输入了0怎么办
class Program { static void Main(string[] args) { try { Console.Write("请输入数字A:"); string strNumberA = Console.ReadLine(); Console.Write("请选择运算符号(+、-、*、/):"); string strOperate = Console.ReadLine(); Console.Write("请输入数字B:"); string strNumberB = Console.ReadLine(); string strResult = ""; switch (strOperate) { case "+": strResult = Convert.ToString (Convert.ToDouble(strNumberA) + Convert.ToDouble(strNumberB)); break; case "-": strResult = Convert.ToString (Convert.ToDouble(strNumberA) - Convert.ToDouble(strNumberB)); break; case "*": strResult = Convert.ToString (Convert.ToDouble(strNumberA) * Convert.ToDouble(strNumberB)); break; case "/": if (strNumberB != "0") strResult = Convert.ToString (Convert.ToDouble(strNumberA) / Convert.ToDouble(strNumberB)); else strResult = "除数不能为0"; break; } Console.WriteLine("结果是:" + strResult); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("您的输入有错:" + ex.Message); } } }
第三章 复制VS 复用
小菜:“我明白了,他说用任意一种面向对象语言实现,那意思就是要用面向对象的编程方法去实现,对吗?OK,
这个我学过,只不过当时我没想到而已。”
大鸟:“所有编程初学者都会有这样的问题,就是碰到问题就直觉的用计算机能够理解的逻辑来描述和表达待解决
的问题及具体的求解过程。这其实是用计算机的方式去思考,比如计算器这个程序,先要求输入两个数和运算符
号,然后根据运算符号判断选择如何运算,得到结果,这本身没有错,但这样的思维却使得我们的程序只为满足实
现当前的需求,程序不容易维护,不容易扩展,更不容易复用。从而达不到高质量代码的要求。”
第四章 业务的封装
小菜:“你的意思是分一个类出来? 哦,对的,让计算和显示分开。”
大鸟:“准确的说,就是让业务逻辑与界面逻辑分开,让它们之间的耦合度下降。只有分离开,才容易达到容易维
护或扩展。”
小菜:“让我来试试看。”
// 黄良帅 class Program { static void Main(string[] args) { try { Console.WriteLine("请输入数字A:"); string numberA = Console.ReadLine(); Console.WriteLine("请输入运算符号( + - * / ):"); string operate = Console.ReadLine(); Console.WriteLine("请输入数字B:"); string numberB = Console.ReadLine(); double result = Operation.GetResult(Convert.ToDouble(numberA), operate, Convert.ToDouble(numberB)); Console.WriteLine(result); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("你的输入有误" + ex.Message); } } } public class Operation { public static double GetResult(double numberA, string operate, double numberB) { double result = 0; switch (operate) { case "+": result = numberA + numberB; break; case "-": result = numberA - numberB; break; case "*": result = numberA * numberB; break; case "/": result = numberA / numberB; break; } return result; } }
第五章 体会简单工厂模式的美妙
利用封装、继承、多态来实现简单的工厂模式
using System; using System.Collections.Generic; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Operation oper = Program.createOperate("-"); oper.NumberA = 1; oper.NumberB = 2; double result = oper.GetResult(); Console.WriteLine(result); Console.ReadLine(); } public static Operation createOperate(string operate) { Operation oper = null; switch (operate) { case "+": { oper = new OperationAdd(); break; } case "-": { oper = new OperationSub(); break; } case "*": { oper = new OperationMul(); break; } case "/": { oper = new OperationDiv(); break; } } return oper; } } class Operation { private double _numberA; private double _numberB; // 数字A public double NumberA { get { return _numberA; } set { this._numberA = value; } } // 数字B public double NumberB { get { return _numberB; } set { this._numberB = value; } } // 运算结果 public virtual double GetResult() { double result = 0; return result; } } class OperationAdd : Operation { public override double GetResult() { double result = 0; result = NumberA + NumberB; return result; } } class OperationSub : Operation { public override double GetResult() { double result = 0; result = NumberA - NumberB; return result; } } class OperationMul : Operation { public override double GetResult() { double result = 0; result = NumberA * NumberB; return result; } } class OperationDiv : Operation { public override double GetResult() { double result = 0; if (NumberB == 0) { throw new Exception("除数不能为0"); } result = NumberA / NumberB; return result; } } }
大鸟: “吼吼,记住哦,编程是一门技术,更加是一门艺术,不能只满足于写完代码运行结果正确就完事,时常考
虑如何让代码更加简炼,更加容易维护,容易扩展和复用,只有这样才可以是真的提高。写出优雅的代码真的是一
种很爽的事情。不过学无止境,其实这才是理解面向对象的开始呢。”
作业:做一个商场收银软件,营业员根据客户购买商品单价和数量,向客户收费。