面向对象设计原则-迪米特法则示例

2023-05-05 14:49:41 浏览数 (2)

假设有一个图书馆系统,其中包含了三个类:Book(书籍)、Library(图书馆)和User(用户)。其中,Book类表示一本书籍,包含了书名、作者等信息;Library类表示一个图书馆,包含了图书馆的名称、地址等信息,同时还有添加书籍、借出书籍等方法;User类表示一个用户,包含了用户的姓名、电话等信息,同时还有借书、还书等方法。下面给出相应的Java代码:

代码语言:javascript复制
public class Book {
    private String title;
    private String author;
    private String publisher;
    
    public Book(String title, String author, String publisher) {
        this.title = title;
        this.author = author;
        this.publisher = publisher;
    }
    
    // 省略其他方法和属性的定义
}

public class Library {
    private String name;
    private String address;
    private List<Book> books;
    
    public Library(String name, String address) {
        this.name = name;
        this.address = address;
        this.books = new ArrayList<>();
    }
    
    public void addBook(Book book) {
        books.add(book);
    }
    
    public void lendBook(Book book, User user) {
        // 省略借出书籍的具体实现
    }
    
    // 省略其他方法和属性的定义
}

public class User {
    private String name;
    private String phone;
    private List<Book> borrowedBooks;
    
    public User(String name, String phone) {
        this.name = name;
        this.phone = phone;
        this.borrowedBooks = new ArrayList<>();
    }
    
    public void borrowBook(Book book, Library library) {
        // 省略借书的具体实现
    }
    
    public void returnBook(Book book, Library library) {
        // 省略还书的具体实现
    }
    
    // 省略其他方法和属性的定义
}

在上述代码中,Book、Library和User三个类之间的关系比较紧密,它们之间的交互比较频繁,没有遵守迪米特法则。下面对该系统进行重构,使用迪米特法则来设计系统。

首先,我们需要引入一个中间对象,来封装Book和User之间的交互。假设该中间对象命名为Borrow,表示借书记录。Borrow对象包含了借书日期、还书日期等信息。同时,Borrow对象还有一个引用Book对象和User对象,用于表示这本书是由哪个用户借阅的。下面给出Borrow类的定义:

代码语言:javascript复制
typescriptCopy codepublic class Borrow {
    private Date borrowDate;
    private Date returnDate;
    private Book book;
    private User user;
    
    public Borrow(Book book, User user) {
        this.book = book;
        this.user = user;
        this.borrowDate = new Date();
    }
    
    public void returnBook() {
        this.returnDate = new Date();
        // 省略还书后的其他处理
    }
    
    // 省略其他方法和属性的定义
}

在上述代码中,Borrow类作为一个中间对象,负责封装Book和User之间的交互。通过引入Borrow类,Book和User之间的交互就变成了间接交互,而不是直接交互。

接下来,我们需要修改Library和User类,使其通过Borrow对象来进行交互。具体地,Library类在借出书籍时,创建一个新的Borrow对象,将这本书和用户信息保存在Borrow对象中。而User类在借书时,先通过Library对象获取这本书的信息,然后创建一个新的Borrow对象,将这本书和用户信息保存在Borrow对象中。下面给出相应的代码:

代码语言:javascript复制
typescriptCopy codepublic class Library {
    private String name;
    private String address;
    private List<Book> books;
    private List<Borrow> borrows;
    
    public Library(String name, String address) {
        this.name = name;
        this.address = address;
        this.books = new ArrayList<>();
        this.borrows = new ArrayList<>();
    }
    
    public void addBook(Book book) {
        books.add(book);
    }
    
    public void lendBook(Book book, User user) {
        // 检查这本书是否可借
        if (!books.contains(book)) {
            throw new IllegalArgumentException("该图书馆没有这本书!");
        }
        for (Borrow borrow : borrows) {
            if (borrow.getBook().equals(book) && borrow.getReturnDate() == null) {
                throw new IllegalArgumentException("这本书已经被借走了!");
            }
        }
        // 创建一个新的借书记录
        Borrow borrow = new Borrow(book, user);
        borrows.add(borrow);
    }
    
    // 省略其他方法和属性的定义
}

public class User {
    private String name;
    private String phone;
    private List<Borrow> borrows;
    
    public User(String name, String phone) {
        this.name = name;
        this.phone = phone;
        this.borrows = new ArrayList<>();
    }
    
    public void borrowBook(Book book, Library library) {
        library.lendBook(book, this);
    }
    
    public void returnBook(Book book, Library library) {
        for (Borrow borrow : borrows){
        if (borrow.getBook().equals(book) && borrow.getReturnDate() == null) {
                borrow.returnBook();
                return;
            }
        }
        throw new IllegalArgumentException("你没有借过这本书!");
    }
    
    // 省略其他方法和属性的定义
}

在上述代码中,Library类的lendBook方法会创建一个新的Borrow对象,将这本书和用户信息保存在Borrow对象中,并将Borrow对象保存到borrows列表中。而User类的borrowBook方法会调用Library类的lendBook方法来借书,然后创建一个新的Borrow对象,将这本书和用户信息保存在Borrow对象中,并将Borrow对象保存到borrows列表中。User类的returnBook方法会遍历borrows列表,查找用户借阅的这本书对应的Borrow对象,并调用Borrow对象的returnBook方法来还书。

通过引入Borrow对象,Book和User之间的交互变成了间接交互,而不是直接交互。这样可以降低类之间的耦合度,提高系统的灵活性和扩展性。此外,Borrow对象还可以承担其他职责,例如记录借书日期和还书日期等信息,方便图书馆管理借阅记录。

0 人点赞