Java学习--设计模式之结构型模式(二)

一、装饰器模式(Decorator Pattern)

  1、概念

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

  2、简介

   意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

   主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

   何时使用:在不想增加很多子类的情况下扩展类。

   应用实例:

    (1)、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。

    (2)、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。

   优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

   缺点:多层装饰比较复杂。

   使用场景:

    (1)、扩展一个类的功能。

    (2)、动态增加功能,动态撤销。

   注意事项:可代替继承。

  3、实例

   我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。RedShapeDecorator 是实现了 ShapeDecorator 的实体类。演示类 DecoratorPatternDemo,我们的演示类使用 RedShapeDecorator 来装饰 Shape 对象。

    

    (1)、创建一个接口Shape

public interface Shape {
   void draw();
}

    (2)、创建接口的实现类

public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Shape: Rectangle");
   }
}
public class Circle implements Shape {

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

    (3)、创建实现了 Shape 接口的抽象装饰类 ShapeDecorator

public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;

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

   public void draw(){
      decoratedShape.draw();
   }
}

    (4)、创建扩展了 ShapeDecorator 类的实体装饰类 RedShapeDecorator 。

public class RedShapeDecorator extends ShapeDecorator {

   public RedShapeDecorator(Shape decoratedShape) {
      super(decoratedShape);
   }

   @Override
   public void draw() {
      decoratedShape.draw();
      setRedBorder(decoratedShape);
   }

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

    (5)、使用 RedShapeDecorator 来装饰 Shape 对象。

public class DecoratorPatternDemo {
   public static void main(String[] args) {

      Shape circle = new Circle();

      Shape redCircle = new RedShapeDecorator(new Circle());

      Shape redRectangle = new RedShapeDecorator(new Rectangle());
      System.out.println("Circle with normal border");
      circle.draw();

      System.out.println("\nCircle of red border");
      redCircle.draw();

      System.out.println("\nRectangle of red border");
      redRectangle.draw();
   }
}

    (6)、演示结果

 1 Circle with normal border
 2 Shape: Circle
 3
 4 Circle of red border
 5 Shape: Circle
 6 Border Color: Red
 7
 8 Rectangle of red border
 9 Shape: Rectangle
10 Border Color: Red

二、外观模式(Facade Pattern)

  1、概念

   外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。

  2、简介

   意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

   主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之相应的接口。

   何时使用:

    (1)、客户端不需要知道系统内部的复杂联系,整个系统只需提供一个"接待员"即可。

    (2)、定义系统的入口。

   如何解决:客户端不与系统耦合,外观类与系统耦合。

   关键代码:在客户端和复杂系统之间再加一层,这一层将调用顺序、依赖关系等处理好。

   应用实例:

    (1)、去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理,就很方便。

    (2)、JAVA 的三层开发模式。

   优点:

    (1)、减少系统相互依赖。

    (2)、提高灵活性。

    (3)、提高了安全性。

   缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

   使用场景:

    (1)、为复杂的模块或子系统提供外界访问的模块。

    (2)、子系统相对独立。

    (3)、预防低水平人员带来的风险。

   注意事项:在层次化结构中,可以使用外观模式定义系统中每一层的入口。

  3、实例

   我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。下一步是定义一个外观类 ShapeMaker。ShapeMaker 类使用实体类来代表用户对这些类的调用。演示类 FacadePatternDemo,我们的演示类使用 ShapeMaker 类来显示结果。

    

    (1)、创建接口 Shape 。

public interface Shape {
   void draw();
}

    (2)、创建实现了 Shape 接口的实现类。

public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Rectangle::draw()");
   }
}
public class Square implements Shape {

   @Override
   public void draw() {
      System.out.println("Square::draw()");
   }
}
public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Circle::draw()");
   }
}

    (3)、创建一个外观类 ShapeMaker 。

public class ShapeMaker {
   private Shape circle;
   private Shape rectangle;
   private Shape square;

   public ShapeMaker() {
      circle = new Circle();
      rectangle = new Rectangle();
      square = new Square();
   }

   public void drawCircle(){
      circle.draw();
   }
   public void drawRectangle(){
      rectangle.draw();
   }
   public void drawSquare(){
      square.draw();
   }
}

    (4)、使用外观类画出各种形状。

public class FacadePatternDemo {
   public static void main(String[] args) {
      ShapeMaker shapeMaker = new ShapeMaker();

      shapeMaker.drawCircle();
      shapeMaker.drawRectangle();
      shapeMaker.drawSquare();
   }
}

    (5)、演示结果

1 Circle::draw()
2 Rectangle::draw()
3 Square::draw()

三、享元模式(Flyweight Pattern)

  1、概念

   享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。

  2、简介

   意图:运用共享技术有效地支持大量细粒度的对象。

   主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

   何时使用:

    (1)、系统中有大量对象。

    (2)、这些对象消耗大量内存。

    (3)、这些对象的状态大部分可以外部化。

    (4)、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。

    (5)、系统不依赖于这些对象身份,这些对象是不可分辨的。

   如何解决:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。

   关键代码:用 HashMap 存储这些对象。

   优点:大大减少对象的创建,降低系统的内存,使效率提高。

   缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

   注意事项:

    (1)、注意划分外部状态和内部状态,否则可能会引起线程安全问题。

    (2)、这些类必须有一个工厂对象加以控制。

  3、实例

   我们将创建一个 Shape 接口和实现了 Shape 接口的实体类 Circle。下一步是定义工厂类 ShapeFactory。ShapeFactory 有一个 Circle 的 HashMap,其中键名为 Circle 对象的颜色。无论何时接收到请求,都会创建一个特定颜色的圆。ShapeFactory 检查它的 HashMap 中的 circle 对象,如果找到 Circle 对象,则返回该对象,否则将创建一个存储在 hashmap 中以备后续使用的新对象,并把该对象返回到客户端。FlyWeightPatternDemo,我们的演示类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(red / green / blue/ black / white),以便获取它所需对象的颜色。

    

    (1)、创建一个接口 Shape。

public interface Shape {
   void draw();
}

    (2)、创建接口的实体类。

public class Circle implements Shape {
   private String color;
   private int x;
   private int y;
   private int radius;

   public Circle(String color){
      this.color = color;
   }

   public void setX(int x) {
      this.x = x;
   }

   public void setY(int y) {
      this.y = y;
   }

   public void setRadius(int radius) {
      this.radius = radius;
   }

   @Override
   public void draw() {
      System.out.println("Circle: Draw() [Color : " + color
         +", x : " + x +", y :" + y +", radius :" + radius);
   }
}

    (3)、创建一个工厂 ShapeFactory ,生成基于给定信息的实体类的对象。

import java.util.HashMap;

public class ShapeFactory {
   private static final HashMap<String, Shape> circleMap = new HashMap<>();

   public static Shape getCircle(String color) {
      Circle circle = (Circle)circleMap.get(color);

      if(circle == null) {
         circle = new Circle(color);
         circleMap.put(color, circle);
         System.out.println("Creating circle of color : " + color);
      }
      return circle;
   }
}

    (4)、使用该工厂,通过传递颜色信息来获取实体类的对象。

public class FlyweightPatternDemo {
   private static final String colors[] =
      { "Red", "Green", "Blue", "White", "Black" };
   public static void main(String[] args) {

      for(int i=0; i < 20; ++i) {
         Circle circle =
            (Circle)ShapeFactory.getCircle(getRandomColor());
         circle.setX(getRandomX());
         circle.setY(getRandomY());
         circle.setRadius(100);
         circle.draw();
      }
   }
   private static String getRandomColor() {
      return colors[(int)(Math.random()*colors.length)];
   }
   private static int getRandomX() {
      return (int)(Math.random()*100 );
   }
   private static int getRandomY() {
      return (int)(Math.random()*100);
   }
}

    (5)、演示结果

 1 Creating circle of color : Black
 2 Circle: Draw() [Color : Black, x : 36, y :71, radius :100
 3 Creating circle of color : Green
 4 Circle: Draw() [Color : Green, x : 27, y :27, radius :100
 5 Creating circle of color : White
 6 Circle: Draw() [Color : White, x : 64, y :10, radius :100
 7 Creating circle of color : Red
 8 Circle: Draw() [Color : Red, x : 15, y :44, radius :100
 9 Circle: Draw() [Color : Green, x : 19, y :10, radius :100
10 Circle: Draw() [Color : Green, x : 94, y :32, radius :100
11 Circle: Draw() [Color : White, x : 69, y :98, radius :100
12 Creating circle of color : Blue
13 Circle: Draw() [Color : Blue, x : 13, y :4, radius :100
14 Circle: Draw() [Color : Green, x : 21, y :21, radius :100
15 Circle: Draw() [Color : Blue, x : 55, y :86, radius :100
16 Circle: Draw() [Color : White, x : 90, y :70, radius :100
17 Circle: Draw() [Color : Green, x : 78, y :3, radius :100
18 Circle: Draw() [Color : Green, x : 64, y :89, radius :100
19 Circle: Draw() [Color : Blue, x : 3, y :91, radius :100
20 Circle: Draw() [Color : Blue, x : 62, y :82, radius :100
21 Circle: Draw() [Color : Green, x : 97, y :61, radius :100
22 Circle: Draw() [Color : Green, x : 86, y :12, radius :100
23 Circle: Draw() [Color : Green, x : 38, y :93, radius :100
24 Circle: Draw() [Color : Red, x : 76, y :82, radius :100
25 Circle: Draw() [Color : Blue, x : 95, y :82, radius :100

四、代理模式(Proxy Pattern)

  1、概念

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

  2、简介

   意图:为其他对象提供一种代理以控制对这个对象的访问。

   主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

   如何解决:增加中间层。

   关键代码:实现与被代理类组合。

   应用实例:

    (1)、Windows 里面的快捷方式。

    (2)、买火车票不一定在火车站买,也可以去代售点。

    (3)、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。

    (4)、spring aop。

   优点:

    (1)、职责清晰。

    (2)、高扩展性。

    (3)、智能化。

   缺点:

    (1)、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

    (2)、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

   使用场景:按职责来划分,通常有以下使用场景:

    (1)、远程代理。

    (2)、虚拟代理。

    (3)、Copy-on-Write 代理。

    (4)、保护(Protect or Access)代理。

    (5)、Cache代理。

    (6)、防火墙(Firewall)代理。

    (7)、同步化(Synchronization)代理。

    (8)、智能引用(Smart Reference)代理。

   注意事项:

    (1)、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

    (2)、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

  3、实例

   我们将创建一个 Image 接口和实现了 Image 接口的实体类。ProxyImage 是一个代理类,减少 RealImage 对象加载的内存占用。ProxyPatternDemo,我们的演示类使用 ProxyImage 来获取要加载的 Image 对象,并按照需求进行显示。

    

    (1)、创建接口。

public interface Image {
   void display();
}

    (2)、创建接口的实现类。

public class RealImage implements Image {

   private String fileName;

   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }

   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }

   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}
public class ProxyImage implements Image{

   private RealImage realImage;
   private String fileName;

   public ProxyImage(String fileName){
      this.fileName = fileName;
   }

   @Override
   public void display() {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}

    (3)、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

public class ProxyPatternDemo {

   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");

      //图像将从磁盘加载
      image.display();
      System.out.println("");
      //图像将不再从磁盘加载
      image.display();
   }
}

    (4)、演示结果

1 Loading test_10mb.jpg
2 Displaying test_10mb.jpg
3
4 Displaying test_10mb.jpg

结构型模式的讲解到此也就结束了,如有问题,还望各位大佬指正。

原文地址:https://www.cnblogs.com/WHL5/p/9195207.html

时间: 2024-10-29 19:11:44

Java学习--设计模式之结构型模式(二)的相关文章

Java经典23种设计模式之结构型模式(二)

接上篇,本文介绍结构型模式里的组合模式.装饰模式.外观模式. 一.组合模式(Composite) 组合模式:将对象组合成树形结构,表示"部分--整体"的层次结构.最终达到单个对象和组合对象的使用具有一致性.单看这句话貌似有点抽象,其实比较简单. 以李云龙的独立团为例,目的要统计赵嘉宇一战共歼灭敌人多少个.最高的级别是团,一个团有若干个营,一个营有若干个排,一个排有若干个战士.(为了简化问题,排下面就不设行政单位了).很自然的,李云龙给营长开会回去给老子统计.营长回去给各个排长开会,赶紧

Java经典23种设计模式之结构型模式(三)------附代理模式、适配器模式、外观模式区别

本文介绍7种结构型模式里的剩下两种:享元模式.代理模式. 一.享元模式FlyWeight 享元模式比较简单且重要,在很多场合都被用到,只不过封装起来了用户看不到.其概念:运用共享内存技术最大限度的支持大量细粒度的对象.这个概念给的有些抽象,说白了就是如果内存中存在某个对象A,如果再次需要使用对象A的时候如果内存中有A这个对象就直接使用它,不要再次new了.如果没有,则重新new一个.基于这个特点,享元模式使用时一般会给待访问对象传递一个Tag,用来标识这个对象,而且要同时使用抽象工厂的方法进行访

Java经典23种设计模式之结构型模式(一)

结构型模式包括7种:适配器模式.桥接模式.组合模式.装饰模式.外观模式.享元模式.代理模式. 本文主要介绍适配器模式和桥接模式. 一.适配器模式(Adapter) 适配器模式其实很简单,就像手机充电器一样,手机需要5V的,而插座出来是220V.因此需要充电器变压就ok.再比如,一个之会说汉语的和一个只会说英语的无法沟通,那就中间请个翻译.所有的交流通过翻译,翻译翻给会说英语的,就能完成一次单项交流的.链接1 中的例子非常生动形象了.总结一下,无非就是有个通用的接口(称为Target),如果一切顺

一起学java设计模式--适配器模式(结构型模式)

适配器模式 现有一个接口DataOperation定义了排序方法sort(int[]) 和查找方法search(int[], int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法,类BinarySearch 的binarySearch(int[], int)方法实现了二分查找算法.现使用适配器模式设计一个系统,在不修改源代码的情况下将类QuickSort和类BinarySearch的方法适配到DataOperation接口中.绘制类图并编程实现. (要求实现

《设计模式》结构型模式1

上篇博文写了创建型模式中的(工厂家族).这次来介绍一下结构型模式.主要从各个模式的含义,优缺点,适用场合及结构图来了解结构型模式. 结构型模式包括有7种模式,适配器模式,外观模式,代理模式,桥接模式,享元模式,组合模式,装饰模式.每个模式各有优缺,孰优孰劣,请看下文. 1.适配器模式 定义:将一个类的接口转换成客户希望的另外一个接口.使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 结构图: 适用于:想要使用一个已存在的类,但接口和你的要求不同时 在软件开发后期或是维护时期,在双方都不

设计模式总结-结构型模式

描述: 如何组合类和对象以获得最大的结构: 不是对接口和实现进行组合,而是描述了如何对一些对象进行组合,从而实现新功能的一些方法: 分类: 适配器模式 http://blog.csdn.net/huo065000/article/details/22177651 装饰模式 http://blog.csdn.net/huo065000/article/details/22061403 代理模式 http://blog.csdn.net/huo065000/article/details/22177

设计模式(27)-----结构型模式-----过滤器模式

过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来.这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准. 实现 我们将创建一个 Person 对象.Criteria 接口和实现了该接口的实体类,来过滤 Person 对象的列表.CriteriaPatternDemo,我们的演示类使用 Criteria 对象,基于各种标准和它们的结合来过滤 Pe

设计模式(28)-----结构型模式-----享元模式

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式. 享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象.我们将通过创建 5 个对象来画出 20 个分布于不同位置的圆来演示这种模式.由于只有 5 种可用的颜色,所以 color 属性被用来检查现有的 Circle 对象.这里只有5个对象的. 介绍 意图:运用共享技术有效地支持大量细粒度的对象. 主

设计模式4 结构型模式

设计模式4  结构型模式 目录 代理模式 装饰器 外观模式 适配器模式 代理模式,美国,韩国代理购物 [email protected]:~$ cat main.cpp  #include<iostream> using namespace std; class Item //商品 { public: Item(string kind ,bool fact) { this->kind = kind; this->fact = fact; } string getKind() { r