访问者模式

简述:

访问者模式是一种行为设计模式,它允许你在不改变元素类的前提下定义新的操作。通过将操作封装在独立的访问者类中,访问者模式可以在不修改元素类的情况下增加新的操作或算法。

在访问者模式中,访问者对象通过访问元素对象的方式来实现对元素对象的不同操作,从而实现了操作和元素对象之间的分离,以及对元素对象行为的扩展。通过将操作集中在访问者对象中,访问者模式可以更好地管理和维护操作的代码,同时使客户端代码保持健壮和清晰。

解决的问题:

1. **添加新的操作**:当需要为现有的元素类添加新的操作时,通常的做法是在元素类中添加新的方法,这样会违反开闭原则,因为每次添加新的操作都需要修改元素类。使用访问者模式,可以通过在访问者类中添加新的操作方法来实现对现有元素类的扩展,而无需修改元素类。

2. **避免操作与元素类耦合**:在访问者模式中,操作被封装在访问者类中,元素类只需接受访问者对象即可执行操作,从而避免了操作与元素类之间的紧耦合关系。这样可以使代码结构更加清晰,并且可以轻松地添加新的操作而不影响元素类。

3. **将操作集中管理**:访问者模式将对元素的操作集中在一个访问者类中,可以更好地管理和维护这些操作。不同类型的操作可以分开实现在不同的访问者类中,使代码结构更加清晰和易于扩展。

模式原理:

1. **元素类(Element)**:元素类是指需要被访问者访问的对象,通常包含一个接受访问者对象的方法,即 `accept(visitor)` 方法。该方法会将自身作为参数传递给访问者对象,并调用访问者对象的操作方法。

2. **访问者接口(Visitor)**:访问者接口定义了访问者对象可以对元素对象进行的操作方法,通常有多个不同的操作方法,每个操作方法对应一个具体的元素类。访问者接口中的操作方法会根据不同的元素对象来执行不同的操作。

3. **具体访问者(Concrete Visitor)**:具体访问者是实现了访问者接口的类,其中实现了对元素对象不同操作的具体逻辑。每个具体访问者类都会实现对元素对象的不同操作方法。

4. **对象结构(Object Structure)**:对象结构是元素对象的集合,通常包含多个不同的元素对象,访问者需要遍历每个元素对象并对其进行操作。对象结构通常会提供方法用于添加、删除、获取元素对象。

5. **具体元素(Concrete Element)**:具体元素是实现了元素接口的类,通常会重写 `accept(visitor)` 方法以调用访问者对象的操作方法。

6. **客户端(Client)**:客户端是使用访问者模式的地方,它会创建具体的元素对象和具体的访问者对象,并将元素对象添加到对象结构中。客户端会调用对象结构中元素对象的 `accept(visitor)` 方法来开始访问者模式的操作。
 

应用场景:

1. **操作和数据结构分离**:当有一个数据结构(对象结构)包含多个不同类型的元素对象,而且需要对这些元素对象进行多种不同的操作时,可以使用访问者模式将操作和数据结构进行分离,使得操作可以独立于数据结构变化而变化。

2. **数据结构稳定,但操作频繁变化**:当数据结构相对稳定,但需要频繁变化或增加新的操作时,可以使用访问者模式。通过定义新的访问者类来实现新的操作,而不需要修改原有的数据结构类。

3. **多个不同的操作需求**:当需要对数据结构中的元素对象进行多种不同类型的操作,而且这些操作之间没有直接关联时,可以使用访问者模式。这样可以将不同类型的操作分离开来,减少代码的复杂度。

4. **增加新的操作而不影响元素类**:当需要添加新的操作而不希望修改元素类的代码时,可以使用访问者模式。通过创建新的访问者类来实现新的操作,而不需要修改原有的元素类。

5. **数据结构与操作耦合性较高**:当数据结构与操作之间的耦合性较高,过多的操作分散到数据结构的类中时,可以通过访问者模式将操作移到独立的访问者类中,降低耦合性。
 

实例讲解:

假设我们有一个电商网站,网站上有多种商品,如电脑、手机、书籍等,我们需要对这些商品进行不同类型的价格计算和折扣操作。我们可以使用访问者模式来实现这一功能。

首先,我们定义一个商品接口 `Product`,包含一个 `accept` 方法接收访问者对象:
 

public interface Product {
    void accept(Visitor visitor);
}

然后,我们定义不同类型的商品类,例如 `Computer`、`Phone`、`Book`,它们实现 `Product` 接口,并根据需要定义自己的属性:

public class Computer implements Product {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    
    // Other computer-related methods and attributes
}

public class Phone implements Product {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    
    // Other phone-related methods and attributes
}

public class Book implements Product {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    
    // Other book-related methods and attributes
}

接下来,我们定义一个访问者接口 `Visitor`,包含多个不同类型的 `visit` 方法,用于对不同商品类型进行操作:

public interface Visitor {
    void visit(Computer computer);
    void visit(Phone phone);
    void visit(Book book);
}

 然后,我们可以实现不同类型的访问者类,例如 `PriceCalculator` 计算商品价格、`DiscountOffer` 提供折扣等:

 

public class PriceCalculator implements Visitor {
    public void visit(Computer computer) {
        // 计算电脑价格
        // code...
    }
    
    public void visit(Phone phone) {
        // 计算手机价格
        // code...
    }
    
    public void visit(Book book) {
        // 计算书籍价格
        // code...
    }
}

public class DiscountOffer implements Visitor {
    public void visit(Computer computer) {
        // 为电脑提供折扣
        // code...
    }
    
    public void visit(Phone phone) {
        // 为手机提供折扣
        // code...
    }
    
    public void visit(Book book) {
        // 为书籍提供折扣
        // code...
    }
}

最后,我们可以在客户端代码中创建商品对象,并根据需要应用不同类型的访问者进行操作:

public class Client {
    public static void main(String[] args) {
        Product computer = new Computer();
        Product phone = new Phone();
        Product book = new Book();
        
        Visitor priceCalculator = new PriceCalculator();
        Visitor discountOffer = new DiscountOffer();
        
        computer.accept(priceCalculator);
        phone.accept(discountOffer);
        book.accept(priceCalculator);
    }
}

通过上述代码,我们实现了对商品对象进行不同类型操作的功能,同时也实现了操作和数据结构的分离,对于不同的操作需求能够独立扩展和修改,符合访问者模式的设计思想。 

 

优点:

1. 分离数据结构和数据操作:访问者模式将数据结构和数据操作分离,使得新增、修改各种操作变得更加容易。数据结构类只需要提供一个接受访问者的方法,而具体的数据操作则由访问者实现。

2. 增加新的操作很容易:可以通过增加新的访问者类来增加新的操作,而不需要修改已有的数据结构类,符合开闭原则。

3. 类型检查容易:由于访问者模式将数据结构和数据操作分开,因此可以通过访问者的类型来判断不同类型的数据操作,使得类型检查更加容易。

缺点:

1. 增加新的数据结构类困难:如果需要增加新的数据结构类,需要同时修改所有的访问者类,这样会使得系统变得复杂,并且容易出错。

2. 破坏封装性:访问者模式中,访问者访问和操作数据结构中的数据,可能会导致一些数据私有性的泄漏,使得数据结构的封装性降低。

3. 增加系统复杂度:引入访问者模式会增加系统中类和接口的数量,使得代码结构变得更加复杂,同时,访问者模式也带来了一定的性能损耗。

总的来说,访问者模式适用于系统中数据结构稳定,但对数据操作进行频繁变更和扩展的场景,能够很好地解耦数据结构和数据操作。但在数据结构变化频繁的情况下,引入访问者模式可能会增加系统复杂度。需要根据具体情况来选择是否使用访问者模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

L.2626

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值