家庭网络做网站,四平市建设局网站,手机可以做网站吗,电商网站建设分析文章目录 一、面向对象设计原则二、模版方法三、策略模式四、观察者模式五、装饰模式六、桥模式七、工厂方法_Factory Method八、抽象工厂_Abstract Factory九、原型模式十、构建器_builder十一、单件模式_Singleton十二、享元模式_Flyweight 一、面向对象设计原则
设计模式的… 文章目录 一、面向对象设计原则二、模版方法三、策略模式四、观察者模式五、装饰模式六、桥模式七、工厂方法_Factory Method八、抽象工厂_Abstract Factory九、原型模式十、构建器_builder十一、单件模式_Singleton十二、享元模式_Flyweight 一、面向对象设计原则
设计模式的八个原则
依赖倒置原则(DIP)高层次的代码稳定不应该依赖低层次的代码变化、抽象的代码不应该依赖具体的代码。开放封闭原则(OCP)类模块应该开放扩展的而其原先的代码尽量封闭不可改变。单一职责原则(SRP)一个类应该仅有一个变化的原因该变化隐含了它的职责职责太多时会导致扩展时对代码东拉西扯造成混乱。替换原则(LSP)子类必须能够替换它的基类IS-A继承可以表达类型抽象。接口隔离原则(ISP)接口应该小而完备不该强迫用户使用多余的方法。优先使用组合而不是继承继承通常会让子类和父类的耦合度增加、组合的方式只要求组件具备良好定义的接口。封装变化点使用封装来创建对象之间的分界层让设计者可以在分界层的一侧进行修改而不会对另一侧产生不良的影响从而实现层次间的松耦合。针对接口编程而不是针对实现编程。使用封装来创建对象之间的分界层让设计者可以在分界层的一侧进行修改而不会对另一侧产生不良的影响从而实现层 次间的松耦合。
设计模式关键重构 重构关键技法 静态-动态 早绑定-晚绑定 继承-组合 编译时依赖-运行时依赖 紧耦合-松耦合
二、模版方法
模式定义 定义一个操作中的算法的骨架 (稳定)而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤。 找到稳定绝大部分时候没有绝对稳定只有相对稳定
要点总结 Template Method模式是一种非常基础性的设计模式在面向对象系统中有着大量的应用。它用最简洁的机制虚函数的多态性为很多应用程序框架提供了灵活的扩展点是代码复用方面的基本实现结构。 除了可以灵活应对子步骤的变化外“不要调用我让我来调用你”的反向控制结构是Template Method的典型应用。 在具体实现方面被Template Method调用的虚方法可以具有实现也可以没有任何实现抽象方法、纯虚方法但一般推荐将它们设置为protected方法。
//应用程序开发人员
class Application : public Library {
protected:virtual bool Step2(){//... 子类重写实现}virtual void Step4() {//... 子类重写实现}
};int main(){Library* pLibnew Application(); //子类中重写父类虚函数后子类指针调用含有父类虚函数的函数则执行重写的函数pLib-Run();delete pLib;}
}//程序库开发人员
class Library{ //稳定即不需要作修改
public://稳定 template method 框架放置2与5待实现 1 3 5稳定的已经实现的,若run不稳定则不采用此模式void Run(){Step1();if (Step2()) { //支持变化 虚函数的多态调用Step3(); }for (int i 0; i 4; i){Step4(); //支持变化 虚函数的多态调用}Step5();}virtual ~Library(){ }protected:void Step1() { //稳定 因此写为实函数//.....}void Step3() {//稳定//.....}void Step5() { //稳定//.....}virtual bool Step2() 0;//变化 //子类中实现virtual void Step4() 0; //变化 //待实现写为虚函数
};
三、策略模式
现代软件专业分工之后的第一个结果是“框架与应用程序的划分”“组件协作”模式通过晚期绑定来实现框架与应用程序之间的松耦合是二者之间协作时常用的模式。
在软件构建过程中某些对象使用的算法可能多种多样经常改变如果将这些算法都编码到对象中将会使对象变得异常复杂而且有时候支持不使用的算法也是一个性能负担。
模式定义 定义一系列算法把它们一个个封装起来并且使它们可互相替换变化。该模式使得算法可独立于使用它的客户程序(稳定)而变化扩展子类化。
要点总结 Strategy及其子类为组件提供了一系列可重用的算法从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。 Strategy模式提供了用条件判断语句以外的另一种选择消除条件判断语句就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。 如果Strategy对象没有实例变量那么各个上下文可以共享同一个Strategy对象从而节省对象开销。 class TaxStrategy{
public:virtual double Calculate(const Context context)0;virtual ~TaxStrategy(){}
};class CNTax : public TaxStrategy{
public:virtual double Calculate(const Context context){//***********}
};class USTax : public TaxStrategy{
public:virtual double Calculate(const Context context){//***********}
};class DETax : public TaxStrategy{
public:virtual double Calculate(const Context context){//***********}
};//扩展
//*********************************
class FRTax : public TaxStrategy{
public:virtual double Calculate(const Context context){//.........}
};class SalesOrder{
private:TaxStrategy* strategy;public:SalesOrder(StrategyFactory* strategyFactory){this-strategy strategyFactory-NewStrategy();}~SalesOrder(){delete this-strategy;}public double CalculateTax(){//...Context context();//输入内容double val strategy-Calculate(context); //多态调用//...}};
四、观察者模式
在软件构建过程中我们需要为某些对象建立一种“通知依赖关系” ——一个对象目标对象的状态发生改变所有的依赖对象观察者对象都将得到通知。如果这样的依赖关系过于紧密将使软件不能很好地抵御变化。 使用面向对象技术可以将这种依赖关系弱化并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。 模式定义 定义对象间的一种一对多变化的依赖关系以便当一个对象(Subject)的状态发生改变时所有依赖于它的对象都得到通知并自动更新。
要点总结 使用面向对象的抽象Observer模式使得我们可以独立地改变目标与观察者从而使二者之间的依赖关系达致松耦合。 目标发送通知时无需指定观察者通知可以携带通知信息作为参数会自动传播。 观察者自己决定是否需要订阅通知目标对象对此一无所知。 Observer模式是基于事件的UI框架中非常常用的设计模式也是MVC模式的一个重要组成部分。
class IProgress{
public:virtual void DoProgress(float value)0;virtual ~IProgress(){}
};
//抽象类加上列表实现的接口class FileSplitter
{string m_filePath;int m_fileNumber;ListIProgress* m_iprogressList; // 抽象通知机制支持多个观察者 基类的指针列表可以放入派生类的指针只能调用基类已有的函数public:FileSplitter(const string filePath, int fileNumber) :m_filePath(filePath), m_fileNumber(fileNumber){}void split(){//1.读取大文件//2.分批次向小文件中写入for (int i 0; i m_fileNumber; i){//...float progressValue m_fileNumber;progressValue (i 1) / progressValue;onProgress(progressValue);//发送通知 具体目标(被观察者)发生改变向观察者发送通知} //目标发送并不指定观察者通知自动传播}void addIProgress(IProgress* iprogress){m_iprogressList.push_back(iprogress);}void removeIProgress(IProgress* iprogress){m_iprogressList.remove(iprogress);}protected:virtual void onProgress(float value){ListIProgress*::iterator itorm_iprogressList.begin(); //迭代器指向待显示进度条的模块类指针while (itor ! m_iprogressList.end() ) //具体DoProgress通过重写在功能类中实现(*itor)-DoProgress(value); //更新进度条 具体观察者依次响应itor;}}
};class MainForm : public Form, public IProgress //多继承的使用应为一个主继承多个子功能继承
{ //子功能通过继承虚基类来将类指针传递给列表功能类上使用列表的迭代器对每个部件进行实现TextBox* txtFilePath; //此处子功能的变化为目标各部件即为观察者TextBox* txtFileNumber;ProgressBar* progressBar;public:void Button1_Click(){string filePath txtFilePath-getText();int number atoi(txtFileNumber-getText().c_str());ConsoleNotifier cn;FileSplitter splitter(filePath, number);splitter.addIProgress(this); //订阅通知 通过继承虚基类的方式将指针放入列表中进行操作splitter.addIProgress(cn) //订阅通知 观察者自行决定是否订阅splitter.split();splitter.removeIProgress(this);}virtual void DoProgress(float value){progressBar-setValue(value);}
};class ConsoleNotifier : public IProgress {
public:virtual void DoProgress(float value){cout .;}
};
五、装饰模式
在某些情况下我们可能会“过度地使用继承来扩展对象的功能” 由于继承为类型引入的静态特质使得这种扩展方式缺乏灵活性 并且随着子类的增多扩展功能的增多各种子类的组合扩展功能的组合会导致更多子类的膨胀。
模式定义 动态组合地给一个对象增加一些额外的职责。 就增加功能而言Decorator模式比生成子类继承更为灵活消除重复代码 减少子类个数。
要点总结 通过采用组合而非继承的手法 Decorator模式实现了在运行时 动态扩展对象功能的能力而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。 Decorator类在接口上表现为is-a Component的继承关系即 Decorator类继承了Component类所具有的接口。但在实现上又 表现为has-a Component的组合关系即Decorator类又使用了 另外一个Component类。 Decorator模式的目的并非解决“多子类衍生的多继承”问题 Decorator模式应用的要点在于解决“主体类在多个方向上的扩展 功能”——是为“装饰”的含义。
举例说明 //业务操作
class Stream{public:virtual char Read(int number)0;virtual void Seek(int position)0;virtual void Write(char data)0;virtual ~Stream(){}
};//主体类
class FileStream: public Stream{
public:virtual char Read(int number){//读文件流}virtual void Seek(int position){//定位文件流}virtual void Write(char data){//写文件流}};class NetworkStream :public Stream{
public:virtual char Read(int number){//读网络流}virtual void Seek(int position){//定位网络流}virtual void Write(char data){//写网络流}};class MemoryStream :public Stream{
public:virtual char Read(int number){//读内存流}virtual void Seek(int position){//定位内存流}virtual void Write(char data){//写内存流}};//扩展操作class DecoratorStream: public Stream{
protected:Stream* stream;//...DecoratorStream(Stream * stm):stream(stm){ //stream stm}};class CryptoStream: public DecoratorStream {public:CryptoStream(Stream* stm):DecoratorStream(stm){}virtual char Read(int number){//额外的加密操作...stream-Read(number);//读文件流 对应主体类不同的具体操作 stream赋值对应类指针}virtual void Seek(int position){//额外的加密操作...stream::Seek(position);//定位文件流//额外的加密操作...}virtual void Write(byte data){//额外的加密操作...stream::Write(data);//写文件流//额外的加密操作...}
};class BufferedStream : public DecoratorStream{Stream* stream;//...public:BufferedStream(Stream* stm):DecoratorStream(stm){}//...
};void Process(){//运行时装配FileStream* s1new FileStream();CryptoStream* s2new CryptoStream(s1);BufferedStream* s3new BufferedStream(s1);BufferedStream* s4new BufferedStream(s2);}六、桥模式
将抽象部分(业务功能)与实现部分(平台实现)分离使它们都可以独立地变化。 模式定义 将抽象部分(业务功能)与实现部分(平台实现)分离使它们都可以独立地变化。
要点总结 Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固 有的绑定关系使得抽象和实现可以沿着各自的维度来变化。所谓 抽象和实现沿着各自纬度的变化即“子类化”它们。 Bridge模式有时候类似于多继承方案但是多继承方案往往违背单一职责原则即一个类只有一个变化的原因复用性比较差。 Bridge模式是比多继承方案更好的解决方法。 Bridge模式的应用一般在“两个非常强的变化维度”有时一个 类也有多于两个的变化维度这时可以使用Bridge的扩展模式。
class Messager{
protected:MessagerImp* messagerImp;//...
public:virtual void Login(string username, string password)0;virtual void SendMessage(string message)0;virtual void SendPicture(Image image)0;virtual ~Messager(){}
};class MessagerImp{
public:virtual void PlaySound()0;virtual void DrawShape()0;virtual void WriteText()0;virtual void Connect()0;virtual MessagerImp(){}
};//平台实现 n
class PCMessagerImp : public MessagerImp{
public:virtual void PlaySound(){//**********}virtual void DrawShape(){//**********}virtual void WriteText(){//**********}virtual void Connect(){//**********}
};class MobileMessagerImp : public MessagerImp{
public:virtual void PlaySound(){//}virtual void DrawShape(){//}virtual void WriteText(){//}virtual void Connect(){//}
};//业务抽象 m//类的数目1nmclass MessagerLite :public Messager {public:virtual void Login(string username, string password){messagerImp-Connect();//........}virtual void SendMessage(string message){messagerImp-WriteText();//........}virtual void SendPicture(Image image){messagerImp-DrawShape();//........}
};class MessagerPerfect :public Messager {public:virtual void Login(string username, string password){messagerImp-PlaySound();//********messagerImp-Connect();//........}virtual void SendMessage(string message){messagerImp-PlaySound();//********messagerImp-WriteText();//........}virtual void SendPicture(Image image){messagerImp-PlaySound();//********messagerImp-DrawShape();//........}
};void Process(){//运行时装配MessagerImp* mImpnew PCMessagerImp();Messager *m new MessagerLite(mImp);
}
七、工厂方法_Factory Method
通过“对象创建” 模式绕开new来避免对象创建new过程中所导致的紧耦合依赖具体类从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
模式定义 定义一个用于创建对象的接口让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟目的解耦手段虚函数到子类。
要点总结 Factory Method模式用于隔离类对象的使用者和具体类型之间的 耦合关系。 面对一个经常变化的具体类型紧耦合关系(new)会导致软件的脆弱。
Factory Method模式通过面向对象的手法将所要创建的具体对象工作延迟到子类 从而实现一种扩展而非更改的策略较好地解决了这种紧耦合关系。
Factory Method模式解决“单个对象”的需求变化。缺点在于要 求创建方法/参数相同。 //抽象类
class ISplitter{
public:virtual void split()0;virtual ~ISplitter(){}
};//工厂基类
class SplitterFactory{
public:virtual ISplitter* CreateSplitter()0;virtual ~SplitterFactory(){}
};//具体类
class BinarySplitter : public ISplitter{};class TxtSplitter: public ISplitter{};class PictureSplitter: public ISplitter{};class VideoSplitter: public ISplitter{};//具体工厂
class BinarySplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new BinarySplitter();}
};class TxtSplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new TxtSplitter();}
};class PictureSplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new PictureSplitter();}
};class VideoSplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new VideoSplitter();}
};class MainForm : public Form
{SplitterFactory* factory;//工厂public:MainForm(SplitterFactory* factory){this-factoryfactory;}void Button1_Click(){ISplitter * splitterfactory-CreateSplitter(); //多态newsplitter-split();}
};
八、抽象工厂_Abstract Factory
在软件系统中经常面临着“一系列相互依赖的对象”的创建工作 同时由于需求的变化往往存在更多系列对象的创建工作。 如何应对这种变化如何绕过常规的对象创建方法(new)提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合
提供一个接口让该接口负责创建一系列“相关或者相互依赖的对象”无需指定它们具体的类。
要点总结 如果没有应对“多系列对象构建”的需求变化则没有必要使用Abstract Factory模式这时候使用简单的工厂完全可以。 “系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。 Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。 //数据库访问有关的基类
class IDBConnection{};class IDBCommand{};class IDataReader{};class IDBFactory{
public:virtual IDBConnection* CreateDBConnection()0;virtual IDBCommand* CreateDBCommand()0;virtual IDataReader* CreateDataReader()0;};//支持SQL Server
class SqlConnection: public IDBConnection{};
class SqlCommand: public IDBCommand{};
class SqlDataReader: public IDataReader{};class SqlDBFactory:public IDBFactory{
public:virtual IDBConnection* CreateDBConnection()0;virtual IDBCommand* CreateDBCommand()0;virtual IDataReader* CreateDataReader()0;};//支持Oracle
class OracleConnection: public IDBConnection{};class OracleCommand: public IDBCommand{};class OracleDataReader: public IDataReader{};class EmployeeDAO{IDBFactory* dbFactory;public:vectorEmployeeDO GetEmployees(){IDBConnection* connection dbFactory-CreateDBConnection();connection-ConnectionString(...);IDBCommand* command dbFactory-CreateDBCommand();command-CommandText(...);command-SetConnection(connection); //关联性IDBDataReader* reader command-ExecuteReader(); //关联性while (reader-Read()){}}
};
九、原型模式
在软件系统中经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化这些对象经常面临着剧烈的变化但是它们却拥有比较稳定一致的接口。 如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象”从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?
使用原型实例指定创建对象的种类然后通过拷贝这些原型来创建新的对象。
要点总结 Prototype模式同样用于隔离类对象的使用者和具体类型(易变类之间的耦合关系它同样要求这些“易变类”拥有“稳定的接口”。 Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象–所需工作仅仅是注册一个***新类的对象(即原型)***然后在任何需要的地方Clone。 Prototype模式中的Clone方法可以利用某些框架中的序列化来实现深拷贝。
十、构建器_builder
在软件系统中有时候面临着“一个复杂对象”的创建工作其通常由各个部分的子对象用一定的算法构成 由于需求的变化这个复杂对象的各个部分经常面临着剧烈的变化但是将它们组合在一起的算法却相对稳定。 如何应对这种变化如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化从而保持系统中的“稳定构建算法”不随着需求改变而改变
将一个复杂对象的构建与其表示相分离使得同样的构建过 程(稳定)可以创建不同的表示(变化)。
要点总结 Builder 模式主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定的算法而复杂对象的各个部分则经常变化。 变化点在哪里封装哪里—— Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。 在Builder模式中要注意不同语言中构造器内调用虚函数的差别C vs. C#) 。 class House{//....
};class HouseBuilder {
public:House* GetResult(){return pHouse;}virtual ~HouseBuilder(){}
protected:House* pHouse;virtual void BuildPart1()0;virtual void BuildPart2()0;virtual void BuildPart3()0;virtual void BuildPart4()0;virtual void BuildPart5()0;};class StoneHouse: public House{};class StoneHouseBuilder: public HouseBuilder{
protected:virtual void BuildPart1(){//pHouse-Part1 ...;}virtual void BuildPart2(){}virtual void BuildPart3(){}virtual void BuildPart4(){}virtual void BuildPart5(){}};class HouseDirector{public:HouseBuilder* pHouseBuilder;HouseDirector(HouseBuilder* pHouseBuilder){this-pHouseBuilderpHouseBuilder;}House* Construct(){pHouseBuilder-BuildPart1();for (int i 0; i 4; i){pHouseBuilder-BuildPart2();}bool flagpHouseBuilder-BuildPart3();if(flag){pHouseBuilder-BuildPart4();}pHouseBuilder-BuildPart5();return pHouseBuilder-GetResult();}
};
十一、单件模式_Singleton
在软件系统中经常有这样一些特殊的类必须保证它们在系统中只存在一个实例才能确保它们的逻辑正确性、以及良好的效率。 如何绕过常规的构造器提供一种机制来保证一个类只有一个实例? 这应该是类设计者的责任而不是使用者的责任。
保证一个类仅有一个实例并提供一个该实例的全局访问点。
要点总结 Singleton模式中的实例构造器可以设置为protected以允许子类派生 Singleton模式一般不要支持拷贝构造函数和Clone接口因为这有可能导致多个对象实例与Singleton模式的初衷违背。 如何实现多线程环境下安全的Singleton?注意对双检查锁的正确实现。
class Singleton{
private:Singleton();Singleton(const Singleton other);
public:static Singleton* getInstance();static Singleton* m_instance;
};Singleton* Singleton::m_instancenullptr;//线程非安全版本
Singleton* Singleton::getInstance() {if (m_instance nullptr) {m_instance new Singleton();}return m_instance;
}//线程安全版本但锁的代价过高
Singleton* Singleton::getInstance() {Lock lock;if (m_instance nullptr) {m_instance new Singleton();}return m_instance;
}//双检查锁但由于内存读写reorder不安全
Singleton* Singleton::getInstance() {if(m_instancenullptr){Lock lock;if (m_instance nullptr) {m_instance new Singleton();}}return m_instance;
}//C 11版本之后的跨平台实现 (volatile)
std::atomicSingleton* Singleton::m_instance;
std::mutex Singleton::m_mutex;Singleton* Singleton::getInstance() {Singleton* tmp m_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);//获取内存fenceif (tmp nullptr) {std::lock_guardstd::mutex lock(m_mutex);tmp m_instance.load(std::memory_order_relaxed);if (tmp nullptr) {tmp new Singleton;std::atomic_thread_fence(std::memory_order_release);//释放内存fencem_instance.store(tmp, std::memory_order_relaxed);}}return tmp;
}十二、享元模式_Flyweight
在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中从而带来很高的运行时代价–主要指内存需求方面的代价。 如何在避免大量细粒度对象问题的同时让外部客户程序仍然能够透明地使用面向对象的方式来进行操作?
运用共享技术有效地支持大量细粒度的对象。
要点总结 面向对象很好地解决了抽象性的问题但是作为一个运行在机器需要考虑对象的代价问题。Flyweight主要解中的程序实决面尚对象的代问题一般不触及面向对象的抽象性问题。
Flyweight采用对象共享的做法来降低系统中对象的个数从而降低细粒度对象给系统带来的内存压力。从而降低细粒度对象给系统带来的内存压力。在具体实现方面要注意对象状态的处理。
对象的数量太大从而导致对象内存开销加大———什么样的数量才算大这需要我们仔细的根据具体应用情况进行评估而不能凭空臆断。 class Font {
private://unique object keystring key;//object state//....public:Font(const string key){//...}
};
ßclass FontFactory{
private:mapstring,Font* fontPool;public:Font* GetFont(const string key){mapstring,Font*::iterator itemfontPool.find(key);if(item!footPool.end()){return fontPool[key];}else{Font* font new Font(key);fontPool[key] font;return font;}}void clear(){//...}
};