软件设计培训总结(一)
什么是软件设计
说不上来,反正目前我靠这个养家糊口。
为什么需要软件设计
“杀死一个程序员不需要子弹,只要变更三次需求。”
因此软件设计的目的就是让程序员活下去!
何时做设计
老师的答案:第一颗子弹
总结一句话就是: 变化驱动设计。讲真,
这种lazy-load的方式还是很适合我这种懒惰的程序员的。在变化到来之前,不需要考虑太多的"以后会不会xxx"这系列问题(除非对你所在的领域非常熟悉,已经有很多的经验可以借鉴和预判)。但是,当第一次变化到来的时候,就需要去分离变化——分离变化,并且在这一变化的方向上设计出“一劳永逸”的架构。
具体怎么做
消除重复!消除重复!消除重复!重复是万恶之源!
隐藏在各种设计模式背后的用意就是提高可重用性,反应在代码上就是减少重复代码。
正交原则
- 最小化重复
- 分离不同的变化方向
- 缩小依赖范围
- 向着稳定的方向依赖
简单设计原则(重要性依次降低)
- 通过所有测试(满足用户需求)
- 尽可能消除重复
- 尽可能清晰表达
- 尽可能减少代码元素
举个例子
比如在我们实战演练的时候,Length与Volume对象需要能够“按照格式A输出到屏幕”。于是,我们“信手拈来”地增加了一个toString()
接口,用来按照固定格式输出到屏幕。
变化总是来的太快——用户需求改了,要求能够“按照格式B输出到屏幕”。这时候我们在写一个toStringB()
吗?那如果后续还有“C格式”、“D格式”、……?好吧,这样自己就会有一堆输出字符串的接口——其实他们都做同一件事情,只不多方式不同罢了。
于是,我们封装了行为“输出到屏幕”——提取出了toString()
方法。为了满足用户对输出格式多样化的需求,我们提供了多个Formatter类——用户需要什么格式,自己new
一个吧!
class Formatter
{
public:
Formatter(){}
~Formatter(){}
string format(int value);
};
class FormatterA : public Formatter
{
public:
string format(int value)
{
return "out put formatter category A.";
}
};
class FormatterB : public Formatter
{
string format(int value)
{
return "out put formatter category B.";
}
};
template <typename Type>
class Quality
{
private:
int value;
Type unit;
protected:
inline int getValue() {return value;}
inline Type getUnit() {return unit;}
public:
Quality(int value, Type unit);
virtual ~Quality();
string toString(const Formatter & formatter) // 用户可以通过不同的formatter来定制输出的格式
{
return formatter.format(this->value);
}
};
// 我们只需要提供Length和Volume的定义
typedef Quality<int> Length;
typedef Quality<int> Volume;
// 补充下用户的使用方法
Length l = Length(1, 9);
l.toString(FormatterA());
l.toString(FormatterB());
网友评论