轻松学习设计模式2

参考:https://www.runoob.com/design-pattern/design-pattern-intro.html

目录

 

一、前言

二、设计模式六大原则

三、模式分类

四、结构型模式解析

1、代理模式

2、适配器模式

3、装饰器模式

3.1、UML图

3.2 模式设计代码解析

3.3 模式调用代码解析 

4、桥接模式

4.1 UML图

4.2 模式实现

4.3 模式调用

5、总结


一、前言

最近重看设计模式感触良多,做软件还是需要多看设计模式的,好处多多,这个轻松学习设计模式的第二篇。

二、设计模式六大原则

这几个原则还是需要重复的。

1.开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。

2.里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。 

3.依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
 

4.接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
 

5.迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6.合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。

三、模式分类

创建型:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式;
结构型:代理模式、适配器模式、装饰器模式、桥接模式、组合模式、享元模式、外观模式;
行为型:观察者模式、模板方法模式、命令模式、状态模式、职责链模式、解释器模式 、中介者模式、访问者模式、策略模式、备忘录模式、迭代器模式;

J2EE 模式:MVC 模式(MVC Pattern)、业务代表模式(Business Delegate Pattern)、组合实体模式(Composite Entity Pattern)、数据访问对象模式(Data Access Object Pattern)、前端控制器模式(Front Controller Pattern)、拦截过滤器模式(Intercepting Filter Pattern)、服务定位器模式(Service Locator Pattern)、传输对象模式(Transfer Object Pattern)。

四、结构型模式解析

1、代理模式

     在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

class Image 
{
   vitrual void display()=0;
}
class RealImage :public Image
 {
 
   
 
   public:
       RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }
 

   public:
      virtual  void display() 
   {
      System.out.println("Displaying " + fileName);
   }
 
   private :
      void loadFromDisk(String fileName)
   {
      System.out.println("Loading " + fileName);
   }
   
  private:
       String fileName;

}

class ProxyImage :public Image
{
 
   private:
     RealImage realImage;
      String fileName;
 
   public:
      ProxyImage(String fileName)
    {
      this.fileName = fileName;
    }

    virtual void display() 
     {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}



   

           从代理模式的实现代码我们可以发现,类RealImage和类ProxyImage都实现了基类的display的接口,ProxyImage中实现是通过使用RealImage对象来实现display接口的。

int main(String[] args)
{
      Image image = new ProxyImage("test_10mb.jpg");
 
      // 图像将从磁盘加载
      image.display(); 
      System.out.println("");
      // 图像不需要从磁盘加载
      image.display();  
   
}

      从代理模式的调用代码我们可以看出,我们只需要使用代理类,不需要和未代理类打交道。

2、适配器模式

class MediaPlayer
 {
   public:
   vitrual void play(String audioType, String fileName)=0;
}


class MediaAdapter : public MediaPlayer
{
 
   AdvancedMediaPlayer advancedMusicPlayer;
 
   public:
     MediaAdapter(String audioType)
   {
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();       
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }  
    }
 

         vitrual void play(String audioType, String fileName) 
       {
          if(audioType.equalsIgnoreCase("vlc")){
             advancedMusicPlayer.playVlc(fileName);
          }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
         }
       } 
}



class AudioPlayer :public MediaPlayer {
   MediaAdapter mediaAdapter; 
 
public:

   vitual void play(String audioType, String fileName)
 {    
 
      //播放 mp3 音乐文件的内置支持
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: "+ fileName);         
      } 
      //mediaAdapter 提供了播放其他文件格式的支持
      else if(audioType.equalsIgnoreCase("vlc") 
         || audioType.equalsIgnoreCase("mp4")){
         mediaAdapter = new MediaAdapter(audioType);
         mediaAdapter.play(audioType, fileName);
      }
      else{
         System.out.println("Invalid media. "+
            audioType + " format not supported");
      }
   }   
}

      从实现模式的代码中我们可以发现,类MediaAdapter 对类AdvancedMediaPlayer 实现了适配,类AudioPlayer 又适配了类MediaAdapter,AudioPlayer 从而实现进行播放不同的格式。

int main() 
{
      AudioPlayer audioPlayer = new AudioPlayer();
 
      audioPlayer.play("mp3", "beyond the horizon.mp3");
      audioPlayer.play("mp4", "alone.mp4");
      audioPlayer.play("vlc", "far far away.vlc");
      audioPlayer.play("avi", "mind me.avi");
}

从调用代码我们可以发现,我们只需要和audioPlayer打交道就可以实现不同格式音乐的播放。从而统一了对外调用。

3、装饰器模式

      装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

3.1、UML图

    

3.2 模式设计代码解析

class Shape 
{
   virtual void draw()=0;
}

class Rectangle :Public Shape {
 
   
   public :
    vitural void draw() {
      System.out.println("Shape: Rectangle");
      }
}

class Circle :public Shape 
{
 
   
   public:
    virtual void draw() {
      System.out.println("Shape: Circle");
     }
}

 class ShapeDecorator: public Shape 
{

 
   public:
     ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
     }

     virtual void draw(){
      decoratedShape.draw();
     }  
   protected:
     Shape decoratedShape;
}


public class RedShapeDecorator :public ShapeDecorator 
{
 

 

   public:
      virtual  void draw() {
      decoratedShape.draw();         
      setRedBorder(decoratedShape);
      }
 
   private:
      void setRedBorder(Shape decoratedShape){
      System.out.println("Border Color: Red");
      }
}

public class TxtShapeDecorator :public ShapeDecorator 
{
 

 

   public:
      virtual  void draw() {
      decoratedShape.draw();         
      setText(decoratedShape);
      }
 
   private:
      void setText(Shape decoratedShape){
      System.out.println("Border Color: Red");
      }
}



      模式设计代码还是比较清晰易懂的,ShapeDecorator是装饰类的抽象基类,它也是集成自shape类的,这样我们就可以设计许多个装饰类从而实现对对象的迭代装饰,就如同一件一件穿衣服一样。

3.3 模式调用代码解析 


int  main() 
{
 
      Shape circle = new Circle();
      ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
      ShapeDecorator redCircleText = new TxtShapeDecorator(redCircle);

      System.out.println("Circle with normal border");
      circle.draw();
 
      System.out.println("\nCircle of red border");
      redCircle.draw();
 
      System.out.println("\nCircle of red border and text");
      redCircleText .draw();
 }

      调用代码也是比较清晰的,我们首先定义了一个circle对象,然后使用RedShapeDecorator和TxtShapeDecorator类对其进行装饰,可以得到一个有边框和文本的圆。

4、桥接模式

     桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

4.1 UML图

4.2 模式实现

class DrawAPI
{
   public:
      virtual void drawCircle(int radius, int x, int y)=0;
}


class RedCircle :public DrawAPI
{
   
   public:
     void drawCircle(int radius, int x, int y) {
      System.out.println("Drawing Circle[ color: red, radius: "
         + radius +", x: " +x+", "+ y +"]");
      }
}


class GreenCircle :public DrawAPI 
{
 
   public:
   virutal void drawCircle(int radius, int x, int y) {
      System.out.println("Drawing Circle[ color: green, radius: "
         + radius +", x: " +x+", "+ y +"]");
    }
}
class Shape 
{
  
   protected:
     Shape(DrawAPI drawAPI){
      this.drawAPI = drawAPI;
     }
   public:
      virtual void draw()=0;  

   protected:
       DrawAPI drawAPI;
}


 class Circle :public Shape 
{

 
   public:
     Circle(int x, int y, int radius, DrawAPI drawAPI) {
      super(drawAPI);
      this.x = x;  
      this.y = y;  
      this.radius = radius;
     }
 
   virtual void draw() {
      drawAPI.drawCircle(radius,x,y);
   }

   private:
       int x, y, radius;
}






    模式实现代码不复杂,上面的代码实现了shape接口和shape绘制实现之间的分离 ,我们可以使用RedCircle和GreenCircle去进行Circle的绘制,灵活性强。

4.3 模式调用


int  main() 
{
      Shape redCircle = new Circle(100,100, 10, new RedCircle());
      Shape greenCircle = new Circle(100,100, 10, new GreenCircle());
 
      redCircle.draw();
      greenCircle.draw();
}

      调用这里我们需要何Shape类、Circle类、RedCircle类和GreenCircle类打交道,桥接接口将接口和实现相分离带来的好处是灵活性强,不利的就是调用方需要打交道的类比较多。

5、总结

    今天分析了几个结构性的设计模式,我们应该根据我们的使用场景灵活选择。结构型设计模式还没介绍完,下次继续。今天就先写到这吧,设计模式估计要写一段时间才能写完了。

猜你喜欢

转载自blog.csdn.net/kupe87826/article/details/108320506