设计模式

  • 什么是设计模式

每一个描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案。这样,你就能一次又一次地使用该方案而不必做重复劳动”。

                                                                                                                                                     ——Christopher Alexander

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

我们在解决问题的时候,常常采取两种方式,一种是分解问题,另一种是抽象。

对于分解来说,其实就是分而治之,把大问题不断的划分为一个又一个的小问题,通过解决分解开的每一个小问题来解决整体的大问题。也就是不断的分工,各司其职来解决问题。

而抽象则属于更高的层次,从我们需要解决的问题出发,在与该问题相关的一组关联对象中提取出主要的或共有的部分――说简单一点,就是用相同的行为来操作不同的对象。

面向对象设计原则

软件设计复杂的根本原因是因为它会遇到各种各样的变化:客户需求变化,技术平台变化,开发团队变化,市场环境变化等等。

抽象思维的最大特点是复用性,也就可以抵御这些变化。在1中我们谈到面向对象是抽象思维实现的基础,先让我们重新认识面向对象:


为了确保设计出来地系统具有抽象思维的特性,面向对象设计中提出了一系列的基本原则作为设计的思想。

(1) 依赖倒置原则(DIP)

  • 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)。
  • 抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。

(2)开放封闭原则(OCP)

  • 对扩展开放,对更改封闭
  • 模块应该是可扩展的,但是不可修改

(3)单一指责原则(SRP)

  • 一个类应该仅有一个引起它变化的原因
  • 变化的方向隐含着类的责任

(4)Liskov替换原则(LSP)

  • 子类必须能够替换他们的基类(is-a)
  • 集成表达抽血类型

(5)接口隔离原则(ISP)

  • 不应该强迫客户程序依赖他们不用的方法
  • 接口应该小而完备

(6)优先使用对象组合,而不是类继承

  • 类继承通常为“白盒复用”,对象组合通常为“黑箱复用”
  • 继承在某种程度上破坏了封装性,子类父类耦合度高
  • 而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低

(7)封装变化点

  • 使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合

(8)针对接口编程,而不是针对实现编程

  • 不讲变量类型声明为某个特定的具体类,而是声明为某个接口
  • 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口
  • 减少系统中个部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案
  • 产业强盛的标志:接口的标准化

GOF-23模式分类

1)从目的来看

  • 创建型(Creational)模式:将对象,从而对应需求变化为对象创建时具体类型的实现引来的冲击。
  • 结构型(Structural)模式:通过类继承或者对象组合的方式来获得更灵活的结构,从而应对需求变化为对象的结构带来的冲击
  • 行为型(Behavioral)模式:通过类继承或者对象组合的方式,来划分类与对象的指责,从而应对需求变化为多个交互的对象带来的冲击。

(2)从范围来看

  • 类模式处理类与子类的静态关系
  • 对象模式处理对象间的动态关系

从封装变化角度对模式分类


重构关键技法:

  • 静态绑定→动态绑定
  • 早绑定→晚绑定
  • 继承关系→组合关系
  • 编译时依赖→运行时依赖
  • 紧耦合→松耦合

组件协作”模式:

  • 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
  • 典型模式:

Template Method
Strategy
Observer
Event。

Template Method

动机(Motivation)

  • 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很大改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
  • 如何在确定稳定操作结构额前提下,来灵活应对各个子步骤的变化或者晚期实现需求?

以具体代码为实例:

//应用程序开发人员
class Application{
public:bool Step2(){//...}void Step4(){//...}
};int main()
{Library lib();Application app();lib.Step1();if (app.Step2()){lib.Step3();}for (int i = 0; i < 4; i++){app.Step4();}lib.Step5();}
//程序库开发人员
class Library{public:void Step1(){//...}void Step3(){//...}void Step5(){//...}
};


Library开发人员需要开发1、3、5三个步骤,Application开发人员开发2、4两个步骤和程序主流程。这种通过应用端对流程框架进行调用的方式,称之为早绑定。

上述代码如何在确定稳定操作结构额前提下,来灵活应对各个子步骤的变化或者晚期实现需求呢?

//应用程序开发人员
class Application : public Library {
protected:virtual bool Step2(){//... 子类重写实现}virtual void Step4() {//... 子类重写实现}
};int main(){Library* pLib=new Application();lib->Run();delete pLib;}
}
//程序库开发人员
class Library{
public://稳定 template methodvoid Run(){Step1();if (Step2()) { //支持变化 ==> 虚函数的多态调用Step3(); }for (int i = 0; i < 4; i++){Step4(); //支持变化 ==> 虚函数的多态调用}Step5();}virtual ~Library(){ }protected:void Step1() { //稳定//.....}void Step3() {//稳定//.....}void Step5() { //稳定//.....}

上述代码在做修改后,Library开发人员需要开发1、3、5三个步骤和程序主流程,Application开发人员只需开发2、4两个步骤。这种将流程放入开发库,由库开发者开发,提供给应用程序开发者调用的方法,称之为晚绑定。


在第一次写的代码中,存在以下两个问题:
第一,对应用程序开发人员来说,需要自己开发其中的2、4两个步骤,要求比较高,需要对库中的函数情况比较了解,而且重写的两个函数的难度也相对较大。
第二,库开发人员和应用程序开发人员开发的内容的耦合度很高,需要由用开发人员来组织整体调用流程,未来程序的扩展性和可维护性的难度都比较大。

而在使用模板方法后,库开发人员对开发库进行了重构,增加量两个虚函数,定义了一个run函数,将之前的主流程放入,从而使流程稳定。同时库开发者不知道应用程序开发者会如何设计2、4步骤,因此将其定义为虚函数。

应用程序开发者只需在子类中重新定义这两个虚函数即可,不需要再去考虑整个流程的实现,有效的降低了开发难度。

模式定义

定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method 使得子类可以在不改变(复用)一个算法的结构即可重新定义(Override 重写)该算法的某些特定步骤。
——《设计模式》GoF


要点总结:

  • Template Method 是一种非常基础性的设计模式,在面向对象的系统中,有着大量的应用。他用最简洁的机制(虚函数的多态性)为很多应用程序的框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
  • 除了可以灵活对应子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是 Template Method 的典型应用。
  • 在具体实现方面,被 Template Method 调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),一般推荐将他们设置为 Protected 方法。

Strategy 策略模式

动机:

  • 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中将会使对象变得异常复杂,而且有时候支持不使用的算法也是一种性能负担。
  • 如何在运行时根据需要透明的更改对象的算法,将算法与对象本身解耦,从而避免上述问题?

定义一系列算法,把它们一个个封装起来,并且使他们互相替换,该模式使得算法可独立于使用它们的客户程序而变化。
————《设计模式》 GoF

enum TaxBase {CN_Tax,US_Tax,DE_Tax,FR_Tax       //更改
};class SalesOrder{TaxBase tax;
public:double CalculateTax(){//...if (tax == CN_Tax){//CN***********}else if (tax == US_Tax){//US***********}else if (tax == DE_Tax){//DE***********}else if (tax == FR_Tax){  //更改//...}//....}};

上述代码在遇到变化时,将要在源代码上进行修改,不能抵御变化,更好的做法是
把它们一个个封装起来,并且使他们互相替换,使得算法可独立于使用它们的客户程序而变化。

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); //多态调用//...}};

使用策略模式,实现了当出现新的变化时,只需要添加新的strategy,无需对已有的算法做任何改动。实现了算法和对象的解耦。

要点总结:

  • strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
  • strategy模式提供了用条件判断语句之外的另一种选择,消除条件判断语句,就是解耦合,含有许多条件判断语句的代码通常都需要strategy模式。
  • 如果strategy对象没有实例变量,那么各个上下文可以共享同一个strategy对象,从而节省对象开销。

Observer观察者模式

动机:

class FileSplitter
{string m_filePath;int m_fileNumber;ProgressBar* m_progressBar;public:FileSplitter(const string& filePath, int fileNumber, ProgressBar* progressBar) :m_filePath(filePath), m_fileNumber(fileNumber),m_progressBar(progressBar){}void split(){//1.读取大文件//2.分批次向小文件中写入for (int i = 0; i < m_fileNumber; i++){//...float progressValue = m_fileNumber;progressValue = (i + 1) / progressValue;m_progressBar->setValue(progressValue);}}
};
class MainForm : public Form
{TextBox* txtFilePath;TextBox* txtFileNumber;ProgressBar* progressBar;public:void Button1_Click(){string filePath = txtFilePath->getText();int number = atoi(txtFileNumber->getText().c_str());FileSplitter splitter(filePath, number, progressBar);splitter.split();}
};
class IProgress{
public:virtual void DoProgress(float value)=0;virtual ~IProgress(){}
};class FileSplitter
{string m_filePath;int m_fileNumber;List<IProgress*>  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){List<IProgress*>::iterator itor=m_iprogressList.begin();while (itor != m_iprogressList.end() )(*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
Bridge

Decorator装饰模式

动机:

模式定义
动态组合地给一个对象增加一些额外的职责,就增加功能而言,Decorator模式比生成子类更为灵活,消除重复代码&减少子类个数。
————《设计模式》 GoF

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 CryptoFileStream :public FileStream{
public:virtual char Read(int number){//额外的加密操作...FileStream::Read(number);//读文件流}virtual void Seek(int position){//额外的加密操作...FileStream::Seek(position);//定位文件流//额外的加密操作...}virtual void Write(byte data){//额外的加密操作...FileStream::Write(data);//写文件流//额外的加密操作...}
};class CryptoNetworkStream : :public NetworkStream{
public:virtual char Read(int number){//额外的加密操作...NetworkStream::Read(number);//读网络流}virtual void Seek(int position){//额外的加密操作...NetworkStream::Seek(position);//定位网络流//额外的加密操作...}virtual void Write(byte data){//额外的加密操作...NetworkStream::Write(data);//写网络流//额外的加密操作...}
};class CryptoMemoryStream : public MemoryStream{
public:virtual char Read(int number){//额外的加密操作...MemoryStream::Read(number);//读内存流}virtual void Seek(int position){//额外的加密操作...MemoryStream::Seek(position);//定位内存流//额外的加密操作...}virtual void Write(byte data){//额外的加密操作...MemoryStream::Write(data);//写内存流//额外的加密操作...}
};class BufferedFileStream : public FileStream{//...
};class BufferedNetworkStream : public NetworkStream{//...
};class BufferedMemoryStream : public MemoryStream{//...
}class CryptoBufferedFileStream :public FileStream{
public:virtual char Read(int number){//额外的加密操作...//额外的缓冲操作...FileStream::Read(number);//读文件流}virtual void Seek(int position){//额外的加密操作...//额外的缓冲操作...FileStream::Seek(position);//定位文件流//额外的加密操作...//额外的缓冲操作...}virtual void Write(byte data){//额外的加密操作...//额外的缓冲操作...FileStream::Write(data);//写文件流//额外的加密操作...//额外的缓冲操作...}
};void Process(){//编译时装配CryptoFileStream *fs1 = new CryptoFileStream();BufferedFileStream *fs2 = new BufferedFileStream();CryptoBufferedFileStream *fs3 =new CryptoBufferedFileStream();}
//业务操作
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 CryptoStream: public Stream {Stream* stream;//...public:CryptoStream(Stream* stm):stream(stm){}virtual char Read(int number){//额外的加密操作...stream->Read(number);//读文件流}virtual void Seek(int position){//额外的加密操作...stream::Seek(position);//定位文件流//额外的加密操作...}virtual void Write(byte data){//额外的加密操作...stream::Write(data);//写文件流//额外的加密操作...}
};class BufferedStream : public Stream{Stream* stream;//...public:BufferedStream(Stream* stm):stream(stm){}//...
};void Process(){//运行时装配FileStream* s1=new FileStream();CryptoStream* s2=new CryptoStream(s1);BufferedStream* s3=new BufferedStream(s1);BufferedStream* s4=new BufferedStream(s2);}
//业务操作
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){//写内存流}};//扩展操作DecoratorStream: public Stream{
protected:Stream* stream;//...DecoratorStream(Stream * stm):stream(stm){}};class CryptoStream: public DecoratorStream {public:CryptoStream(Stream* stm):DecoratorStream(stm){}virtual char Read(int number){//额外的加密操作...stream->Read(number);//读文件流}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* s1=new FileStream();CryptoStream* s2=new CryptoStream(s1);BufferedStream* s3=new BufferedStream(s1);BufferedStream* s4=new BufferedStream(s2);}

结构:

  • 要点总结

Bridge桥模式

  • 动机


模式定义
将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化
————《设计模式》GoF

class Messager{
public:virtual void Login(string username, string password)=0;virtual void SendMessage(string message)=0;virtual void SendPicture(Image image)=0;virtual void PlaySound()=0;virtual void DrawShape()=0;virtual void WriteText()=0;virtual void Connect()=0;virtual ~Messager(){}
};//平台实现class PCMessagerBase : public Messager{
public:virtual void PlaySound(){//**********}virtual void DrawShape(){//**********}virtual void WriteText(){//**********}virtual void Connect(){//**********}
};class MobileMessagerBase : public Messager{
public:virtual void PlaySound(){//==========}virtual void DrawShape(){//==========}virtual void WriteText(){//==========}virtual void Connect(){//==========}
};//业务抽象class PCMessagerLite : public PCMessagerBase {
public:virtual void Login(string username, string password){PCMessagerBase::Connect();//........}virtual void SendMessage(string message){PCMessagerBase::WriteText();//........}virtual void SendPicture(Image image){PCMessagerBase::DrawShape();//........}
};class PCMessagerPerfect : public PCMessagerBase {
public:virtual void Login(string username, string password){PCMessagerBase::PlaySound();//********PCMessagerBase::Connect();//........}virtual void SendMessage(string message){PCMessagerBase::PlaySound();//********PCMessagerBase::WriteText();//........}virtual void SendPicture(Image image){PCMessagerBase::PlaySound();//********PCMessagerBase::DrawShape();//........}
};class MobileMessagerLite : public MobileMessagerBase {
public:virtual void Login(string username, string password){MobileMessagerBase::Connect();//........}virtual void SendMessage(string message){MobileMessagerBase::WriteText();//........}virtual void SendPicture(Image image){MobileMessagerBase::DrawShape();//........}
};class MobileMessagerPerfect : public MobileMessagerBase {
public:virtual void Login(string username, string password){MobileMessagerBase::PlaySound();//********MobileMessagerBase::Connect();//........}virtual void SendMessage(string message){MobileMessagerBase::PlaySound();//********MobileMessagerBase::WriteText();//........}virtual void SendPicture(Image image){MobileMessagerBase::PlaySound();//********MobileMessagerBase::DrawShape();//........}
};void Process(){//编译时装配Messager *m =new MobileMessagerPerfect();
}
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//类的数目:1+n+mclass 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* mImp=new PCMessagerImp();Messager *m =new Messager(mImp);
}
  • 结构

  • 要点总结

boolan 设计模式笔记相关推荐

  1. 设计模式笔记——代理模式

    设计模式笔记--代理模式 代理模式介绍 代理模式通常是介于请求方和提供方的一个中介系统,请求方是发送请求的一方,提供方是根据请求提供相应资源的一方 Web中的代理服务器就是一个例子,客户端向代理服务器 ...

  2. Java设计模式笔记——七个结构型模式

    系列文章目录 第一章 Java设计模式笔记--七大设计原则 第二章 Java设计模式笔记--六个创建型模式 文章目录 系列文章目录 一.适配器模式 1.概念 2.类适配器 3.对象适配 4.缺省适配器 ...

  3. 软件设计师——设计模式笔记上

    软件设计师--设计模式笔记上(创造型5种) 设计模式的主要目的 设计模式的原则 1.工厂方法模式(类模式) 意图 适用性 代码实现 2.抽象工厂模式(对象模式) 意图 适用性 代码实现 3.生成器模式 ...

  4. 设计模式笔记(1)---开篇(文章索引)

    概念 设计模式描述了软件设计过程中某一类常见问题的一般性的解决方案. 面向对象的设计模式描述了面向对象设计过程中,在特定场景下类与相互通讯的对象之间常见的组织关系. 设计模式与面向对象 面向对象设计模 ...

  5. java观察者模式本质_6.[研磨设计模式笔记]观察者模式

    1.定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新. 2.解决问题 --订阅报纸 看起来订阅者是直接根有据打交道,但实际上,订阅者的订阅数据 ...

  6. grasp设计模式应用场景_grasp设计模式笔记回顾

    根据讲师所讲做了一下笔记以便自己能方便学习: ------------------------------------------grasp设计模式: grasp(general responsibi ...

  7. 设计模式笔记六:适配器模式

    原文:http://www.runoob.com/design-pattern/ 少许个人理解,如有错误请指出(本文基本照搬,因为比较简单) 适配器模式(Adapter Pattern)是作为两个不兼 ...

  8. 3. 狂神的设计模式笔记-代理模式

    文章目录 一.静态代理 1.1 角色分析: 1.2 代码实现 创建客户 1.3 深入理解静态代理 二.动态代理 2.1 代码实现 本文笔记来自于:狂神的设计模式 代理模式的分类: 静态代理 动态代理 ...

  9. 【笔记】设计模式 | 5种设计模式笔记整理

    跟着b站的设计模式教程学的,以下是目前学习了的5种设计模式的笔记整理 设计模式简介 软件设计的现状:由于客户需求等原因需要频繁的变更软件内部的代码.所以能否设计出复用性尽可能高的程序以解决软件设计的复 ...

最新文章

  1. 真的汉子不多,褚时健褚老算一个
  2. 【读书笔记】.Net并行编程高级教程--Parallel
  3. Linux find和grep的区别
  4. MyCAT全局序列号-数据库方式
  5. windows Service 之调试过程
  6. NHibernate初学者指南(18):验证单个属性
  7. 【转】Windows Phone在隔离存储里存取图片文件
  8. python贝叶斯分析方法实例_python 贝叶斯分析对应的代码
  9. 一、数据库之理论基础
  10. JUST技术:基于HMM的实时地图匹配
  11. R16之Access to Unlicensed Spectrum(3)
  12. GNN手写字体识别java_深度之眼Paper带读笔记GNN.09.GGNN
  13. javascript中使用枚举定义一个对象进行数据转换
  14. Device /dev/sdc excluded by a filter.
  15. 面向对象编程和泛型编程
  16. 大数据安全审计——公安敏感数据的守护神
  17. 迪士尼业务部门大变革,即将强推流媒体
  18. houdini-与unity交互
  19. leetcode190颠倒二进制位(JAVA版)
  20. 2022化工自动化控制仪表操作证考试题库及模拟考试

热门文章

  1. 月份对比_行业洞察 | 10月份行业概览amp;头部广告主盘点
  2. string是python内置函数吗_Python 字符串与内置函数(方法)
  3. c语言语法sc,适合于嵌入式系统的C语言单元测试框架:SCUNIT
  4. 六年级下册百分数计算题_六年级数学上册期末试卷(附答案)
  5. protobuf3 自定义option_ProtoBuf3语法指南(Protocol Buffers)_下
  6. networkx怎么显示图_如何将标签添加到networkx图形中的节点?
  7. python不能复制粘贴_你知道怎么使用python实现复制粘贴的功能吗?
  8. python调用函数获取最开始的异常_Python使用sys.exc_info()方法获取异常信息
  9. DG Lecture 2 part 2: points, vectors, directional derivative
  10. ros melodic学习之plugin