• 软件设计模式(六):迭代器、访问者、建造者模式


    前言

            在这篇文章中,荔枝将会介绍有关迭代器模式、访问者模式和建造者模式的相关知识,其中迭代器和建造者相对来说用的比较多,访问者模式相对来说使用的比较少。重点还是需要理解不同模式的特点吧~希望能帮助到有需要的小伙伴~~~


    文章目录

    前言

    一、迭代器模式Iterator

    二、访问者模式Visitor

    三、建造者模式Builder

    总结


    一、迭代器模式Iterator

            迭代器模式一般用于容器和容器遍历,在基本的数据结构的底层一般都曹勇了迭代器模式。迭代器模式的应用是为我们提供一种方法顺序访问一个聚合对象中的各个元素,而又无需明确对象内部的遍历逻辑。

    为了更好理解这种软件设计模式,我们看看这么一组demo:

    首先创建两个接口,一个是迭代器接口Iterator_,另一个是数据结构的总接口Collection_

            再定义两个容器类ArrayList_和LinkedList_,这两个类实现Collection_接口,该接口中定义了对容器中的数据进行添加的操作、得到容器大小的操作、以及通过Iterator接口的方法提供了遍历的接口方法。通过实现Collection_接口并重写该接口中的方法得到两个容器类。

    ArrayList_ 

    1. package com.crj.Iterator;
    2. class ArrayList_ implements Collection_ {
    3. Object[] objects = new Object[10];
    4. //objects中下一个空的位置在哪儿,或者说,目前容器中有多少个元素
    5. private int index = 0;
    6. public void add(Object o) {
    7. if(index == objects.length) {
    8. Object[] newObjects = new Object[objects.length*2];
    9. System.arraycopy(objects, 0, newObjects, 0, objects.length);
    10. objects = newObjects;
    11. }
    12. objects[index] = o;
    13. index ++;
    14. }
    15. public int size() {
    16. return index;
    17. }
    18. @Override
    19. public Iterator_ iterator() {
    20. return new ArrayListIterator();
    21. }
    22. private class ArrayListIterator implements Iterator_{
    23. private int currentIndex = 0;
    24. @Override
    25. public boolean hasNext() {
    26. if(currentIndex >= index) return false;
    27. return true;
    28. }
    29. @Override
    30. public Object next() {
    31. Object o = objects[currentIndex];
    32. currentIndex ++;
    33. return o;
    34. }
    35. }
    36. }

    LinkedList_ 

    1. package com.crj.Iterator;
    2. /**
    3. * 相比数组,这个容器不用考虑边界问题,可以动态扩展
    4. */
    5. class LinkedList_ implements Collection_ {
    6. Node head = null;
    7. Node tail = null;
    8. //目前容器中有多少个元素
    9. private int size = 0;
    10. public void add(Object o) {
    11. Node n = new Node(o);
    12. n.next = null;
    13. if(head == null) {
    14. head = n;
    15. tail = n;
    16. }
    17. tail.next = n;
    18. tail = n;
    19. size++;
    20. }
    21. private class Node {
    22. private Object o;
    23. Node next;
    24. public Node(Object o) {
    25. this.o = o;
    26. }
    27. }
    28. public int size() {
    29. return size;
    30. }
    31. @Override
    32. public Iterator_ iterator() {
    33. return null;
    34. }
    35. }

    main类

    1. package com.crj.Iterator;
    2. import java.util.Iterator;
    3. public class Main {
    4. public static void main(String[] args) {
    5. Collection_ list = new ArrayList_();
    6. for(int i=0; i<15; i++) {
    7. list.add(new String("s" + i));
    8. }
    9. System.out.println(list.size());
    10. //这个接口的调用方式:
    11. Iterator_ it = list.iterator();
    12. while(it.hasNext()) {
    13. Object o = it.next();
    14. System.out.println(o);
    15. }
    16. }
    17. }

            在main中我们可以看到,我们并不需要知晓两个容器类中各自封装的逻辑以及相应的遍历容器内部元素的逻辑实现,我们只需要通过.next()这种类似指针的迭代器方法就可以获取到容器中的元素,这就是迭代器模式。


    二、访问者模式Visitor

            在结构不变的情况下动态改变对于内部元素动作的模式,Visitor模式比较适合结构不变的类对象的使用,对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。访问者模式在日常的使用中比较少,它的一个主要的应用场景是做编译器Compiler。这个模式理解起来比较简单,下面我们通过一些代码示例来了解。

    1. public class VisitorPatternDemo {
    2. public static void main(String[] args) {
    3. ComputerPart computer = new Computer();
    4. computer.accept(new ComputerPartDisplayVisitor());
    5. }
    6. }
    7. /*
    8. * 接口
    9. */
    10. interface ComputerPart {
    11. public void accept(ComputerPartVisitor computerPartVisitor);
    12. }
    13. /*
    14. * 接口实现类
    15. */
    16. class Keyboard implements ComputerPart {
    17. @Override
    18. public void accept(ComputerPartVisitor computerPartVisitor) {
    19. computerPartVisitor.visit(this);
    20. }
    21. }
    22. class Mouse implements ComputerPart {
    23. @Override
    24. public void accept(ComputerPartVisitor computerPartVisitor) {
    25. computerPartVisitor.visit(this);
    26. }
    27. }
    28. /*
    29. * 访问者接口
    30. */
    31. interface ComputerPartVisitor {
    32. public void visit(Mouse mouse);
    33. public void visit(Keyboard keyboard);
    34. }
    35. //实现类
    36. class ComputerPartDisplayVisitor implements ComputerPartVisitor {
    37. @Override
    38. public void visit(Mouse mouse) {
    39. System.out.println("Displaying Mouse.");
    40. }
    41. @Override
    42. public void visit(Keyboard keyboard) {
    43. System.out.println("Displaying Keyboard.");
    44. }
    45. }

    不同的访问者接口提供了相应的实现类,通过将访问者接口实现类实例化对象传入ComputerPart的实例化方法中,实现接口相应的方法的调用。


    三、建造者模式Builder

            建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。针对的场景:对于一个类的对象的构建方法中需要传递许多的参数,为了简写demo我们可以通过链式调用生成多个对象的方式来得到最后的复杂类对象的构建。我们可以通过一个demo示例来理解:

    首先定义一个TerrainBuilder接口,该接口定义了四个接口方法

    1. package com.crj.builder;
    2. public interface TerrainBuilder {
    3. TerrainBuilder buildWall();
    4. TerrainBuilder buildFort();
    5. TerrainBuilder buildMine();
    6. Terrain build();
    7. }

    接着定义接口的实现类,该接口实现类实现了TerrainBuilder接口,demo中对四种接口方法进行了方法重写,最后再build()方法中会将terrain对象返回

    1. package com.crj.builder;
    2. public class ComplexTerrainBuilder implements TerrainBuilder {
    3. Terrain terrain = new Terrain();
    4. @Override
    5. public TerrainBuilder buildWall() {
    6. terrain.w = new Wall(10, 10, 50, 50);
    7. return this;
    8. }
    9. @Override
    10. public TerrainBuilder buildFort() {
    11. terrain.f = new Fort(10, 10, 50, 50);
    12. return this;
    13. }
    14. @Override
    15. public TerrainBuilder buildMine() {
    16. terrain.m = new Mine(10, 10, 50, 50);
    17. return this;
    18. }
    19. @Override
    20. public Terrain build() {
    21. return terrain;
    22. }
    23. }

    对象类

    1. package com.crj.builder;
    2. public class Terrain {
    3. Wall w;
    4. Fort f;
    5. Mine m;
    6. }
    7. class Wall {
    8. int x, y, w, h;
    9. public Wall(int x, int y, int w, int h) {
    10. this.x = x;
    11. this.y = y;
    12. this.w = w;
    13. this.h = h;
    14. }
    15. }
    16. class Fort {
    17. int x, y, w, h;
    18. public Fort(int x, int y, int w, int h) {
    19. this.x = x;
    20. this.y = y;
    21. this.w = w;
    22. this.h = h;
    23. }
    24. }
    25. class Mine {
    26. int x, y, w, h;
    27. public Mine(int x, int y, int w, int h) {
    28. this.x = x;
    29. this.y = y;
    30. this.w = w;
    31. this.h = h;
    32. }
    33. }

    定义main类

    1. package com.crj.builder;
    2. public class Main {
    3. public static void main(String[] args) {
    4. TerrainBuilder builder = new ComplexTerrainBuilder();
    5. Terrain t = builder.buildFort().buildMine().buildWall().build();
    6. }
    7. }

    在main类中,我们可以看到Terrain类对象的实例化是借助于一连串链式的调用方式,而不是传统的调用含参构造函数来实现的。 


    总结

    对于设计模式我们其实需要了解理论即可,不需要区分的特别开,因为不同的软件代码模式往往都包含着多种设计模式。在学习设计模式时还是比较枯燥的哈哈,整理输出后,希望荔枝不会这么快忘记哈哈哈

    今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

  • 相关阅读:
    进程和线程的主要区别
    7.自定义凸多边形
    计算机视觉项目-实时目标追踪
    北工大汇编——综合题(1)
    mPEG-Cholesterol mPEG-CLS 甲氧基-聚乙二醇-胆固醇科研专用
    【小爱学大数据】FlinkKafkaConsumer
    利用js和audio标签读取音频文件并计算音频时长
    Ubuntu服务器的GitLab部署
    requests从一个链接下载存放在临时文件tempfile,python
    【考研】数据结构考点——直接选择排序
  • 原文地址:https://blog.csdn.net/qq_62706049/article/details/132782793