如何写出灵活、可复用、可扩展、可维护的代码呢?
前言:要想写出灵活、可复用、可扩展、可维护的代码实属不易,到了这个境界那便是是传说中的程序员了(见下图)!哈哈哈。。。希望大家每天都向她发起冲锋的号角,直至胜利的那一天!前一段时间研究了很长一段时间面向对象,感觉收获颇丰,站在巨人的肩膀上看对象,感觉妙极了。今天再次站在巨人的肩膀上看设计模式,励志要把对象设计的更好!!!!!
面向对象设计原则
- 单一责任原则:个类有且只有一个职责
- 开闭原则:软件实体(类,模块,函数等)应该对扩展开放,对修改关闭
- 里氏替换原则:子类型必须能够替换它们的基类(使用基类引用的函数必须能够使用派生类而无须了解派生类)
- 接口隔离原则:用户不应该被迫依赖他们不使用的接口
- 依赖倒置原则:高层次的模块不应该依赖于低层次的模块,而是,都应该依赖于抽象
- 组合替代继承:用组合比用继承好
- 笛米特法则:类对其它类知道的越少越好
- 共同封闭原则:相关类应该一起打包
- 稳定抽象原则:类越稳定,就越应该是抽象类
详情参见下文:
面向对象设计模式
入门须知
设计模式并不是被科学家发明和创造的东西。他们只是被“发现”而已。也就是说,对任何一个普通的问题场景,肯定会有一些好的设计方案。如果我们能识别出一个能解决某个新问题的面向对象设计,那我们就定义了一个新的设计模式。
设计模式不是基于理论发明的。相反,总是先有问题场景,再基于需求和情景不断演化设计方案,最后把一些方案标准化成“模式”。所以,我们讨论每一个设计模式时,要尽量用生活中的真实问题来理解和分析。然后尝试一步步地阐述设计,并以一个能匹配某些模式的设计收尾。
媳妇: 我有点好奇。你不是说有很多模式么,干嘛先说桥梁模式呢?有什么特别重要的原因吗?
丈夫: 问得好。我从桥梁模式开始,而不是其它模式,只有一个原因。我觉得它是所有面向对象设计模式的基础。因为:
它能教你如何抽象地思维,这可是OO设计模式的关键。
它实现了基本的OOD原则。
它很好理解。
如果你能正确地理解它,学习其它模式就易如反掌了。
详情参见下文:
桥接模式
1、桥接模式:将抽象部分和它的实现部分分离,使它们都可以独立的变化。简单粗暴的说,就是抽象对外提供调用的接口;对外隐瞒实现部分,在抽象中引用实现部分,从而实现抽象对实现部分的调用,而抽象中引用的实现部分可以在今后的开发过程中,切换成别的实现部分。(《设计模式:可复用面向对象软件的基础》)
2、UML类图:
3、代码实例:(引用原文代码,只是添加注释)
/*
** FileName : BridgePatternDemo
** Author : Jelly Young
** Date : 2013/12/4
** Description : More information (http://www.jellythink.com/)
** Author : Aidan Dai
** Date : 2015/11/20
** Description : 添加注释(http://www.jellythink.com/archives/132)
*/
#include <iostream>
using namespace std;
/*
** 实现(颜料)
*/
class Implementor
{
public:
virtual void OperationImpl() = 0;
};
/*
** 具体实现(黄色颜料、绿色颜料、蓝色颜料)
*/
class ConcreteImpementor : public Implementor
{
public:
void OperationImpl()
{
cout << "OperationImpl" << endl;
}
};
/*
** 抽象(平面图形)
** 维护一个指向具体实现的指针(黄色颜料、绿色颜料、蓝色颜料)
*/
class Abstraction
{
public:
Abstraction(Implementor *pImpl) : m_pImpl(pImpl){}
virtual void Operation() = 0;
protected:
Implementor *m_pImpl;
};
/*
** 被提炼的抽象(圆形、正方形、长方形)
*/
class RedfinedAbstraction : public Abstraction
{
public:
RedfinedAbstraction(Implementor *pImpl) : Abstraction(pImpl){}
void Operation()
{
m_pImpl->OperationImpl();
}
};
int main(void)
{
Implementor *pImplObj = new ConcreteImpementor();
Abstraction *pAbsObj = new RedfinedAbstraction(pImplObj);
pAbsObj->Operation();
delete pImplObj;
pImplObj = NULL;
delete pAbsObj;
pAbsObj = NULL;
return 0;
}
详情参见下文:
观察者模式
1、观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。当一个对象发生了变化,关注它的对象就会得到通知;这种交互也称为发布-订阅(publish-subscribe)。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者。(《设计模式:可复用面向对象软件的基础》)
2、UML类图:
3、观察这模式调用时序图
4、代码实例:(引用原文代码,只是添加注释)
/*
** FileName : ObserverPatternDemo
** Author : Jelly Young
** Date : 2014/2/14
** Description : More information (http://www.jellythink.com/archives/359)
** Author : Aidan Dai
** Date : 2015/11/21
** Description : 添加注释(Aidan Dai)
*/
#include <iostream>
#include <list>
using namespace std;
//观察者抽象类接口(Aidan Dai)
class Observer
{
public:
virtual void Update(int) = 0;
};
//订阅者抽象类接口(Aidan Dai)
class Subject
{
public:
virtual void Attach(Observer *) = 0;
virtual void Detach(Observer *) = 0;
virtual void Notify() = 0;
};
//观察者抽象类接口实现1(Aidan Dai)
class ConcreteObserver : public Observer
{
public:
//观察订阅者抽象类接口的实现(Aidan Dai)
ConcreteObserver(Subject *pSubject) : m_pSubject(pSubject){}
//记录订阅者抽象类接口的实现的变化(Aidan Dai)
void Update(int value)
{
cout << "ConcreteObserver get the update. New State:" << value << endl;
}
private:
//维护的订阅者抽象类接口的实现(Aidan Dai)
Subject *m_pSubject;
};
//观察者抽象类接口实现2(Aidan Dai)
class ConcreteObserver2 : public Observer
{
public:
ConcreteObserver2(Subject *pSubject) : m_pSubject(pSubject){}
void Update(int value)// 响应变更(Aidan Dai)
{
cout << "ConcreteObserver2 get the update. New State:" << value << endl;
}
private:
Subject *m_pSubject;
};
//订阅者抽象类接口实现(Aidan Dai)
class ConcreteSubject : public Subject
{
public:
void Attach(Observer *pObserver);//添加变更(队列)(Aidan Dai)
void Detach(Observer *pObserver);//移除已响应变更(Aidan Dai)
void Notify();// 通过变更队列指挥观察者响应变更(Aidan Dai)
void SetState(int state)//变更(Aidan Dai)
{
m_iState = state;
}
private:
std::list<Observer *> m_ObserverList;// 变更队列(Aidan Dai)
int m_iState;
};
void ConcreteSubject::Attach(Observer *pObserver)
{
m_ObserverList.push_back(pObserver);// push_back() : insert element at end(Aidan Dai)
}
void ConcreteSubject::Detach(Observer *pObserver)
{
m_ObserverList.remove(pObserver);// romve() : erase each element matching _Val(Aidan Dai)
}
void ConcreteSubject::Notify()
{
std::list<Observer *>::iterator it = m_ObserverList.begin();
while (it != m_ObserverList.end())
{
(*it)->Update(m_iState);
++it;
}
}
int main()
{
// Create Subject
ConcreteSubject *pSubject = new ConcreteSubject();
// Create Observer
Observer *pObserver = new ConcreteObserver(pSubject);
Observer *pObserver2 = new ConcreteObserver2(pSubject);
/* original article
// Change the state
pSubject->SetState(2);
// Register the observer
pSubject->Attach(pObserver);
pSubject->Attach(pObserver2);
pSubject->Notify();
// Unregister the observer
pSubject->Detach(pObserver);
// Change the state
pSubject->SetState(3);
pSubject->Notify();
*/
// Subject should register the Observer at first ! but without change, it would be waste of memory.( Aidan Dai )
// Register the observer
pSubject->Attach(pObserver);
pSubject->Attach(pObserver2);
// Change the state
pSubject->SetState(2);
pSubject->Notify();
delete pObserver;
delete pObserver2;
delete pSubject;
}
详情参见下文:
MV*架构模式
通过以上的学习,现在对面向对象又有了点新的认识!最经典的依旧是面向对象中的封装、继承和多态;分清楚什么关系是is a,什么是has a,也就时要遵循面向对象的设计原则。
就像《我给媳妇解释设计模式:第一部分》文中所说的一样,设计模式的产生是先有问题场景,再基于需求和情景不断演化设计方案,最后把一些方案标准化成“模式”,要理解设计模式还学结合生活中的实力加以分析和运用,但不断的实战中加深对那些经典的设计模式的理解!今天又一次站在了巨人的肩膀上看对象,希望有一天能造个好的对象!
学习了这么多,还是赶快进入正题题吧!
MVC
早在上个世纪70年代,美国的施乐公司(Xerox)的工程师研发了Smalltalk编程语言,并且开始用它编写图形界面的应用程序。而在Smalltalk-80这个版本的时候,一位叫Trygve Reenskaug的工程师设计了MVC图形应用程序的架构模式,极大地降低了图形应用程序的管理难度。而在四人帮(GoF)的设计模式当中并没有把MVC当做是设计模式,而仅仅是把它看成解决问题的一些类的集合。Smalltalk-80 MVC和GoF描述的MVC是最经典的MVC模式。
1、MVC的依赖关系
2、MVC的调用关系
MVC Model [1|2]
1、MVC Model 1 和 MVC Model 2的调用关系
2、基于Thinkphp来理解MVC Model 2
- (1) browser->controller->view->browser
第1步是显而易见的,就像我们现在的团队网站,但你访问时www.lsgogroup.com时实际上是访问www.lsgogroup.com/index.php?s=/Home/Index/index.html,也就是Home模块下的IndexController的index成员(这是个例外,此时直接1->3->5);由此看来第二步和第四步是可以没有的,此时第Controller层仅仅只是路由作用,当然也有可能有些逻辑处理(处理路由)
- (1) browser->controller->model->(data source->controller->)view->browser
第1步是显而易见的,就像我们现在的团队网站,但你访问时http://www.lsgogroup.com/index.php?s=/Blog/Index/index.html时,也就是Blog模块下的IndexController的index成员;此时Controller层只是不仅起路由作用,还要获取model层的数据,去渲染view层
个人认为Thinkphp更倾向于MVP架构模式,只是个人愚见,欢迎大家交流讨论。。。
MVP
- MVP模式有两种:
1、MVP(Passive View)
2、MVP(Supervising Controller)
MVP(Passive View)
MVP(Passive View)的依赖关系
MVP(Passive View)的调用关系
MVP(Supervising Controller)
MVP(Supervising Controller)的依赖和调用关系
MVVM
- MVVM代表的是Model-View-ViewMode(第一次听说时,小白犯错了)
结束语:
在本次学习中,自己只是结合大神们的原创总结了下,记录了重点,也可以说是思维导图吧!方便小白们学习,请大神们原谅我的盗图,再此感谢原创博主们为此付出的努力,对他们的分享精神致已崇高的敬意!
理想是丰满的,现实是骨感的。经过,闯过,才会真正的明白这句话后面的意味。现在在连二线城市都算不上的呼和浩特,干着自己算不上非常喜欢的工作,还好,还是自己喜欢的圈子,还能做自己喜欢的事情。离家也不远(180KM),每个星期都可以回去看看年迈的父母,尽尽孝心,有时候想想,这也不错哦。
外面花花的世界,对我还是有非常大的诱惑,有颗不安分的心,还有热血在流淌着,但现实是我快当爸爸了;有时候不敢想,如果我去了北京工作,她和我的小baby还在千里之外的家里,那是一种什么样的感觉。
理想还是要有的,万一实现了呢,你说呢!!!
本文参考以下博文:
1、我是怎样教媳妇面向对象编程的
2、我给媳妇解释设计模式:第一部分
3、于大连:C++设计模式——桥接模式
4、于大连:C++设计模式——观察者模式
5、戴嘉华:界面之下:还原真实的MV*模式
6、阮一峰:谈谈MVC模式
7、阮一峰:MVC,MVP 和 MVVM 的图示