栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式详解(二):结构型模式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式详解(二):结构型模式

结构型模式

结构型模式主要关注的问题是如果组合各种对象来获得更加合适的结构,它不仅仅是简单地使用继承,更多的是通过组合于运行期间的动态组合来实现灵活的功能

适配器模式

将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

主要将现存的对象放在一个新环境中,满足现对象的需求。

它可以让任意两个没有关系的类一起运行,提高类的复用性,有更好的灵活性。但是过多的使用适配器会很难理解代码,不明白各接口是不是真的是本身还是适配了别的接口,而且java的单继承机制表明,一个适配器类只能有一个目标抽象类

  • 现有两个播放器,一个普通的,一个高级的两个接口

    public interface MediaPlayer {
       public void play(String audioType, String fileName);
    }
    
    public interface AdvancedMediaPlayer {    
       public void playVlc(String fileName);
       public void playMp4(String fileName);
    }
    
  • 高级播放器接口的两种播放方式实体类

    public class VlcPlayer implements AdvancedMediaPlayer{
       @Override
       public void playVlc(String fileName) {
          System.out.println("Playing vlc file. Name: "+ fileName);      
       }
    
       @Override
       public void playMp4(String fileName) {
          //什么也不做
       }
    }
    
    public class Mp4Player implements AdvancedMediaPlayer{
    
       @Override
       public void playVlc(String fileName) {
          //什么也不做
       }
    
       @Override
       public void playMp4(String fileName) {
          System.out.println("Playing mp4 file. Name: "+ fileName);        
       }
    }
    
  • 普通播放器适配器适配了高级播放器的功能,适配器类

    public class MediaAdapter implements MediaPlayer {
    
       AdvancedMediaPlayer advancedMusicPlayer;
    
       public MediaAdapter(String audioType){
          if(audioType.equalsIgnoreCase("vlc") ){
             advancedMusicPlayer = new VlcPlayer();          
          } else if (audioType.equalsIgnoreCase("mp4")){
             advancedMusicPlayer = new Mp4Player();
          }  
       }
    
       @Override
       public void play(String audioType, String fileName) {
          if(audioType.equalsIgnoreCase("vlc")){
             advancedMusicPlayer.playVlc(fileName);
          }else if(audioType.equalsIgnoreCase("mp4")){
             advancedMusicPlayer.playMp4(fileName);
          }
       }
    }
    
  • 普通播放器接口的实体类

    public class AudioPlayer implements MediaPlayer {
       MediaAdapter mediaAdapter; 
    
       @Override
       public 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");
          }
       }   
    }
    
  • 用普通播放器实现类来播放不同的音乐格式

    public class AdapterPattern{
       public static void main(String[] args) {
          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");
       }
    }
    
  • 得到结果

    Playing mp3 file. Name: beyond the horizon.mp3
    Playing mp4 file. Name: alone.mp4
    Playing vlc file. Name: far far away.vlc
    Invalid media. avi format not supported

桥接模式

将抽象部分与实现部分分离,使它们都可以独立的变化。

桥接模式实现抽象和实现的分离,它的内部实现细节对用户透明,并且拥有很强的扩展能力,

  • 桥接模式接口

    public interface DrawAPI {
       public void drawCircle(int radius, int x, int y);
    }
    
  • 接口的不同类型的实体类

    public class RedCircle implements DrawAPI {
       @Override
       public void drawCircle(int radius, int x, int y) {
          System.out.println("Drawing Circle[ color: red, radius: "
             + radius +", x: " +x+", "+ y +"]");
       }
    }
    
    public class GreenCircle implements DrawAPI {
       @Override
       public void drawCircle(int radius, int x, int y) {
          System.out.println("Drawing Circle[ color: green, radius: "
             + radius +", x: " +x+", "+ y +"]");
       }
    }
    
  • 创建一个抽象类调用桥接模式的接口来使用它的功能

    public abstract class Shape {
       protected DrawAPI drawAPI;
       protected Shape(DrawAPI drawAPI){
          this.drawAPI = drawAPI;
       }
       public abstract void draw();   
    }
    
  • 创建这个抽象类的实体类

    public class Circle extends Shape {
       private int x, y, radius;
    
       public Circle(int x, int y, int radius, DrawAPI drawAPI) {
          super(drawAPI);
          this.x = x;  
          this.y = y;  
          this.radius = radius;
       }
    
       public void draw() {
          drawAPI.drawCircle(radius,x,y);
       }
    }
    
  • 调用不同的方法来得到不同的结果

    public class BridgePatternDemo {
       public static void main(String[] args) {
          Shape redCircle = new Circle(100,100, 10, new RedCircle());
          Shape greenCircle = new Circle(100,100, 10, new GreenCircle());
    
          redCircle.draw();
          greenCircle.draw();
       }
    }
    
  • 输出如下

    Drawing Circle[ color: red, radius: 10, x: 100, 100]
    Drawing Circle[ color: green, radius: 10, x: 100, 100]

过滤器模式

使用不同标准来过滤一组对象,通过运算逻辑以解耦的方式将它们联系起来。

它通过制定不同的规则来实现过滤,并且对过滤的结果进行分组

这里不curd代码了,写一下它和aop之间的联系

  • AOP

    我们在学习spring中,遇到spring的两大特性之一aop,也就是面向切面编程,实质上是将程序的树状结构的任意一个位置横切功能,在不影响原来项目的前提下,对功能进行添加

    一般有Filter和代理模式两种常见的使用方式,也就是过滤器和拦截器,过滤器基于的是回调函数,代理模式是基于java反射技术,代理模式详见Spring三天入门(二):代理模式,动态代理,spring实现AOP,切入

  • 过滤器

    过滤器是J2EE的规范,它位于客户端和web应用之间,基于Servlet,通过回调方式可以过滤请求和图片等,每一个请求一个过滤器过滤一次,请求过滤后可以交给拦截器,过滤器只在容器初始化的时候初始化一次,请求一次就调用一次

组合模式

将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

它把一组相似的对象当成一个单一的对象,根据树形结构来组合对象,高层模块调用简单。但是使用组合模式后,类的声明都是实现类,不是接口,违反了依赖倒置原则。

  • 创建一个类,这个类里有各种结构

    import java.util.ArrayList;
    import java.util.List;
    
    public class Employee {
       private String name;
       private String dept;
       private int salary;
       private List subordinates;
    
       //构造函数
       public Employee(String name,String dept, int sal) {
          this.name = name;
          this.dept = dept;
          this.salary = sal;
          subordinates = new ArrayList();
       }
    
       public void add(Employee e) {
          subordinates.add(e);
       }
    
       public void remove(Employee e) {
          subordinates.remove(e);
       }
    
       public List getSubordinates(){
         return subordinates;
       }
    
       public String toString(){
          return ("Employee :[ Name : "+ name 
          +", dept : "+ dept + ", salary :"
          + salary+" ]");
       }   
    }
    
  • 另一个类放入数据打印结果

    public class CompositePattern {
       public static void main(String[] args) {
          Employee CEO = new Employee("John","CEO", 30000);
    
          Employee headSales = new Employee("Robert","Head Sales", 20000);
    
          Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
    
          Employee clerk1 = new Employee("Laura","Marketing", 10000);
          Employee clerk2 = new Employee("Bob","Marketing", 10000);
    
          Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
          Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
    
          CEO.add(headSales);
          CEO.add(headMarketing);
    
          headSales.add(salesExecutive1);
          headSales.add(salesExecutive2);
    
          headMarketing.add(clerk1);
          headMarketing.add(clerk2);
    
          //打印该组织的所有员工
          System.out.println(CEO); 
          for (Employee headEmployee : CEO.getSubordinates()) {
             System.out.println(headEmployee);
             for (Employee employee : headEmployee.getSubordinates()) {
                System.out.println(employee);
             }
          }        
       }
    }
    
装饰器模式

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

它通过新建一个装饰类,来包装原有的类,并且在保持类方法签名完整性的情况下,提供额外的功能。

提高了灵活性安全性,但是不符合开闭原则。

  • 一个公共接口和两个不同特性的实体类

    public interface Shape {
       void draw();
    }
    
    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");
       }
    }
    
  • 该接口的装饰器抽象类

    public abstract class ShapeDecorator implements Shape {
        protected Shape decoratedShape;
    
        public ShapeDecorator(Shape decoratedShape){
            this.decoratedShape = decoratedShape;
        }
    
        public void draw(){
            decoratedShape.draw();
        }
    }
    
  • 装饰器实体类

    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");
        }
    }
    
  • 测试结果,调用实体类

    public class DecoratorPattern {
        public static void main(String[] args) {
    
            Shape circle = new Circle();
            ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
            ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
            //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();
        }
    }
    
  • 测试结果

    Circle of red border
    Shape: Circle
    Border Color: Red

    Rectangle of red border
    Shape: Rectangle
    Border Color: Red

外观模式

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

隐藏系统的复杂性,给用户提供可以访问系统的接口,减少了系统的相互依赖,提高灵活性,但是不符合开闭原则

java的三层开发模式即dao到service到controller也属于外观模式

  • 创建Shape接口和三个不同的实体类同上

  • 外观类,类似于实体类

    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();
        }
    }
    
  • 外观模式直接调用

    public class FacadePattern{
        public static void main(String[] args) {
            ShapeMaker shapeMaker = new ShapeMaker();
    
            shapeMaker.drawCircle();
            shapeMaker.drawRectangle();
            shapeMaker.drawSquare();
        }
    }
    
  • 结果如下

    Inside Circle::draw() method.
    Inside Rectangle::draw() method.
    Inside Square::draw() method.

享元模式

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

减少创建对象的数量,把对象中有共同的部分抽象出来,降低系统内存,但是提高了项目的复杂度

  • 一个接口和对应的实体类

    public interface Shape {
        void draw();
    }
    
    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);
        }
    }
    
  • 创建一个工厂结构,将创造的对象放进HashMap中

    import java.util.HashMap;
     
    public class ShapeFactory {
       private static final HashMap 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;
       }
    }
    
  • 放入对象得到结果

    public class FlyweightPattern {
        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);
        }
    }
    
  • 结果如下

    Creating circle of color : Blue
    Circle: Draw() [Color : Blue, x : 51, y :92, radius :100
    Creating circle of color : White
    Circle: Draw() [Color : White, x : 90, y :74, radius :100
    Circle: Draw() [Color : White, x : 79, y :78, radius :100
    Circle: Draw() [Color : Blue, x : 65, y :50, radius :100
    Creating circle of color : Red
    Circle: Draw() [Color : Red, x : 22, y :37, radius :100
    Circle: Draw() [Color : Blue, x : 49, y :10, radius :100
    Creating circle of color : Green
    Circle: Draw() [Color : Green, x : 98, y :43, radius :100
    Creating circle of color : Black
    Circle: Draw() [Color : Black, x : 58, y :25, radius :100
    Circle: Draw() [Color : Black, x : 60, y :35, radius :100
    Circle: Draw() [Color : Red, x : 44, y :26, radius :100
    Circle: Draw() [Color : White, x : 77, y :16, radius :100
    Circle: Draw() [Color : Black, x : 39, y :73, radius :100
    Circle: Draw() [Color : Blue, x : 18, y :40, radius :100
    Circle: Draw() [Color : Blue, x : 71, y :77, radius :100
    Circle: Draw() [Color : Blue, x : 42, y :0, radius :100
    Circle: Draw() [Color : Green, x : 42, y :25, radius :100
    Circle: Draw() [Color : White, x : 24, y :76, radius :100
    Circle: Draw() [Color : White, x : 72, y :0, radius :100
    Circle: Draw() [Color : Red, x : 60, y :42, radius :100
    Circle: Draw() [Color : Red, x : 87, y :14, radius :100

代理模式

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

一个类代表另一个类的功能,并且可以自定义额外的操作,可以见Spring三天入门(二):代理模式,动态代理,spring实现AOP,切入

  • 抽象接口

    public interface Image {
        void display();
    }
    
  • 实体类,分为真实角色,和代理角色

    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();
        }
    }
    
  • 通过代理角色来获取真实角色的对象

    public class ProxyPattern {
    
        public static void main(String[] args) {
            Image image = new ProxyImage("test_10mb.jpg");
    
            // 图像将从磁盘加载
            image.display();
            System.out.println("");
            // 图像不需要从磁盘加载
            image.display();
        }
    }
    
  • 得到结果如下

    Loading test_10mb.jpg
    Displaying test_10mb.jpg

    Displaying test_10mb.jpg

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/302198.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号