(1)单一职责原则(SRP)
就一个类而言,应该仅有一个引起它变化的原因。
(2)开发-封闭原则(OCP)
软件实体(类、模板、函数等)应该是可以扩展的,但是不可修改的。
即对扩展开发,对更改封闭。
实例说明:Shape应用程序
①违反OCP
②
③问题:如果所有圆必须在正方形之前绘制,那么该怎么处理呢?
实例代码:
(注意:关于typeid的错误(warning C4541: 'typeid' used on polymorphic type 'class A' with /GR-; unpredictable behavior may result)
可能在写程序用到typeid的时候遇到这种警告
运行的时候就会出现致命错误
解决方法:在vc6中.
Project - settings... - C/C++
在Category那里选 C++ Language
再在下边勾上 Enable Run-Time Type Information[RTTI] )
//shap.h
#ifndef _SHAPE_H
#define _SHAPE_H
#include <typeinfo>
#include <string>
#include <iostream>
using namespace std;
class Shape
{
public :
virtual void Draw() = 0 ;
bool Precedes(const Shape &)const;
bool operator<(const Shape & s)const
{
return Precedes(s);
}
private :
static const char * typeOrderTable[];
} ;
#endif
//shape.cpp
#include "Shape.h"
#include "Circle.h"
#include "Square.h"
#include <iostream>
using namespace std;
const char* Shape::typeOrderTable[] =
{
typeid(Circle).name(),
typeid(Square).name(),
0
};
bool Shape:: Precedes(const Shape & s) const
{
const char * thisType = typeid(*this).name();
const char * argType = typeid(s).name();
bool done = false ;
int thisOrd = -1 ;
int argOrd = -1 ;
for ( int i = 0 ; !done ; i++)
{
const char * tableEntry = typeOrderTable[i] ;
if(tableEntry != 0 )
{
if(strcmp(tableEntry,thisType)==0)
thisOrd = i ;
if(strcmp(tableEntry,argType)==0)
argOrd = i ;
if( ( argOrd >=0) && ( thisOrd >= 0 ))
done = true ;
}
else //tableEntry == 0
done = true ;
}
return thisOrd < argOrd ;
//return (thisOrd < argOrd) ;
}
//Circle.h
#ifndef _CIRCLE_H
#define _CIRCLE_H
#include "Shape.h"
class Circle: public Shape
{
private:
int r;
public : void Draw();
};
#endif
//Circle.cpp
#include "Circle.h"
#include <iostream>
using namespace std;
void Circle::Draw()
{
cout<<"画一个圆\n"<<endl;
}
//squaer.h 和square.cpp和Circle.h和Circle.cpp类似
//test.cpp
#include "Shape.h"
#include "Circle.h"
#include "Square.h"
#include <iostream>
#include<vector>
#include <algorithm>
using namespace std;
template <typename P>
class Lessp
{
public :
bool operator()(const P p, const P q ){ return (*p) < (*q);}
};
void DrawAllShapes(vector<Shape *>&list)
{
vector<Shape*> orderedList = list ;
sort(orderedList.begin(),
orderedList.end(),
Lessp<Shape*>());
vector<Shape*>::const_iterator i;
for(i=orderedList.begin() ; i!=orderedList.end();i++)
{
(*i)->Draw();
}
}
void main()
{
vector<Shape*> list ;
Shape *c1= new Circle();
Shape *c2= new Circle();
Shape *c3= new Circle();
Shape *s1= new Square();
Shape *s2= new Square();
Shape *s3= new Square();
list.push_back(c1);
list.push_back(s2);
list.push_back(s1);
list.push_back(c2);
list.push_back(s3);
list.push_back(c3);
DrawAllShapes(list);
}
运行结果
(3)Liskov替换原则(LSP)
子类型必须能够替换掉它们的基类型。
启发式规则和习惯用法:
其一:完成的功能少于其基类的派生类通常是不能替换其基类的,因此就违反了LSP。如下
public class Base
{
public void f(){/**some code */}
}
public class Derived extends Base
{
public void f(){}
}
其二:在派生类的方法中添加了其基类不会抛出的异常。
(4)依赖倒置原则
抽象不应该依赖于细节,细节应该依赖于抽象。
模板方法的缺点:
HEADER 和THERMOMETER的类型不能在运行时更改;
对于新类型的HEADER 或者THERMOMETER的使用会迫使重新编译和重新部署。所以除非有非常严格的速度性能要求,否则应优先使用动态多态性。
(5)接口隔离原则(ISP)