设计模式学习(1)适应设计模式

迭代器模式

  • Iterator 迭代器接口

    public interface Iterator{
        boolean hasNext();	// 是否有下一个元素
        Object next();		// 返回下一个元素
    }
    
  • Aggregate 集合接口

    // 集合接口
    public interface Aggregate{
        Iterator iterator();
    }
    

例子

Iterator有个问题是:

  • 迭代器的next如何实现?保存集合的引用以及相关的信息,后面的例子会看到
  • 集合需要保存迭代器的引用吗? 不用,每次调用iterator获取迭代器的时候直接new一个就可以了

下面我们用迭代器模式来实现遍历书架上的书

class Book {
    private String name;

    public Book(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

class BookShelf implements Aggregate {
    private Book[] books;
    private int bookNumber;

    public BookShelf(int capacity) {
        books = new Book[capacity];
        bookNumber = 0;
    }

    public Book getBook(int index) {
        return books[index];
    }

    public void addBook(Book book) {
        books[bookNumber++] = book;
    }

    public int length() {
        return bookNumber;
    }

    @Override
    public Iterator iterator() {
        return new BookShelfIterator(this);
    }
}

class BookShelfIterator implements Iterator {

    private BookShelf bookShelf;
    private int index;

    BookShelfIterator(BookShelf shelf) {
        bookShelf = shelf;
        index = 0;
    }

    @Override
    public boolean hasNext() {
        return index < bookShelf.length();
    }

    @Override
    public Object next() {
        return bookShelf.getBook(index++);
    }
}

// main函数
public class IteratorTest {
    public static void main(String[] args) {
        Book book1 = new Book("English");
        Book book2 = new Book("Math");
        Book book3 = new Book("Chinese");

        BookShelf bookShelf = new BookShelf(10);
        bookShelf.addBook(book1);
        bookShelf.addBook(book2);
        bookShelf.addBook(book3);

        Iterator bookIterator = bookShelf.iterator();
        while (bookIterator.hasNext()) {
            System.out.println(bookIterator.next());
        }
    }
}

角色

  • Iterator 迭代器接口
  • Aggregate 集合接口
  • 具体的Iterator,上例是BookShelfIterator
  • 具体的Aggregate,上例是BookShelf

注意

  • 引入迭代器后,可以将遍历单独分离开,因为遍历方式可能会有很多种,for循环遍历是最基础的一种。
  • Iterator会保存Aggregate的引用,所以它知道怎么在Aggregate中获取元素。那么当Aggregate获取元素的方法改变后,Iterator也要变
  • next不是返回下一个元素,而是返回当前,并指向下一个
  • 当next指向的元素超过了集合范围,hasNext就应该返回false
  • 迭代器可以next遍历,也可以previous遍历,有的还能跳跃式遍历

相关设计模式

  • 访问者模式Visitor
  • 组合模式Composite
  • 工厂方法Factory Method

适配器模式

我们现在想要实现printWeak和printStrong两个打印方法。这两个方法已经在Banner中实现了,但是接口不同。在Banner中实现的名字叫showWithParen和showWithAster。

现在我们想通过一个适配器,把这俩接口名改过来

// 横幅类
// 提供了两种显示的方法
// 但是这两个接口与我们希望的不符合
class Banner{
    private String string; // 横幅的内容
    public Banner(String str) {
        string = str;
    }

    // 圆括号显示
    public void showWithParen(){
        System.out.println("(" + string + ")");
    }

    // 星号显示
    public void showWithAster(){
        System.out.println("*" + string + "*");
    }
}

interface Print{
    void printWeak();
    void printStrong();
}

class PrintBanner extends Banner implements Print{

    public PrintBanner(String str) {
        super(str);
    }

    @Override
    public void printWeak() {
        showWithParen();
    }

    @Override
    public void printStrong() {
        showWithAster();
    }
}

public class AdaptorTest {
    public static void main(String[] args) {
        PrintBanner printBanner = new PrintBanner("ahahaha");
        printBanner.printWeak();
        printBanner.printStrong();
    }
}

上面这种实现方式是通过继承原类,并实现接口。下面还有一种是通过委托的方法

abstract class Print{
    public abstract void printWeak();
    public abstract void printStrong();
}

class PrintBanner extends Print{
    Banner banner;
    public PrintBanner(String str) {
        banner = new Banner(str);
    }

    @Override
    public void printWeak() {
        banner.showWithParen();
    }

    @Override
    public void printStrong() {
        banner.showWithAster();
    }
}

角色

继承版本的

委托版本的,与继承不同的地方是

  • Adapter不再是接口,而是抽象类
  • Adapter拥有了一个原类的对象

注意

  • 使用适配器是为了不修改源码,当我们需要使用某个库,但是又不是很喜欢它的接口,可以用适配器做一个包装。
  • 适配器的好处是,源库没有动,只需要测试适配器即可。只要源码动了,不管是改了什么,都需要做测试
  • 版本升级的时候,为了与旧版本兼容,可以在新版本上写一个适配器来适配旧版本。

相关设计模式

桥接模式:将功能与实现分离

装饰器模式:在不改变接口的情况下,增加新的功能

posted @ 2022-08-13 15:22  Destiny233  阅读(38)  评论(0)    收藏  举报