桥接模式
桥接模式适合解决两个维度的问题,可以使问题在两个维度上无限扩张,并且可以随意组合,比如下表:
发送消息的方式 | 紧急 | 一般 |
---|---|---|
邮件 | 紧急消息邮件发送 | 一般消息邮件发送 |
短信 | 紧急消息短信发送 | 一般消息短信发送 |
类图特别像一个桥梁:
桥接模式必须由一方使用抽象类,持有使用接口的一方,建议描述动作的一方使用接口,描述形态的一方使用抽象类
消息类:
public abstract class AbstractMessage {
private String message;
private MessageSender sender;
public AbstractMessage(String message, MessageSender sender) {
this.message = message;
this.sender = sender;
}
public void send() {
sender.send(message);
}
}
public class SpecialMessage extends AbstractMessage {
public SpecialMessage(String message, MessageSender sender) {
super("特别消息:" + message, sender);
}
}
public class CommonMessage extends AbstractMessage {
public CommonMessage(String message, MessageSender sender) {
super("普通消息:" + message, sender);
}
}
消息发送方式类:
public interface MessageSender {
public void send(String message);
}
public class MailMessageSender implements MessageSender {
@Override
public void send(String message) {
System.out.println("使用邮件发送消息:" + message);
}
}
public class SMSMessageSender implements MessageSender {
@Override
public void send(String message) {
System.out.println("使用短信发送消息:" + message);
}
}
客户端类:
public static void main(String[] args) {
AbstractMessage message = new CommonMessage("message1", new MailMessageSender());
message.send();
message = new CommonMessage("message1", new SMSMessageSender());
message.send();
message = new SpecialMessage("message2", new MailMessageSender());
message.send();
message = new SpecialMessage("message2", new SMSMessageSender());
message.send();
}
输出:
使用邮件发送消息:普通消息:message1
使用短信发送消息:普通消息:message1
使用邮件发送消息:特别消息:message2
使用短信发送消息:特别消息:message2
装饰者模式
装饰者模式和桥接模式很像,也是解决两个维度问题,使两个维度可以自由扩展和组合
类图:
从外观上看装饰者模式和桥接模式的类图只有一个地方不一样,就是最上边的接口和抽象类间的关系,装饰者模式是实现接口,桥接是以组合的方式持有接口
被装饰类:
public interface Conponent {
public int read();
}
public class ConcreteConponent1 implements Conponent {
@Override
public int read() {
return 95;
}
}
public class ConcreteConponent2 implements Conponent {
@Override
public int read() {
return 96;
}
}
装饰者:
public abstract class AbstractDecorator implements Conponent {
protected Conponent conponent;
public AbstractDecorator(Conponent conponent) {
this.conponent = conponent;
}
}
public class ConcreteDecorator1 extends AbstractDecorator {
public ConcreteDecorator1(Conponent conponent) {
super(conponent);
}
@Override
public int read() {
return conponent.read() - 1;
}
}
public class ConcreteDecorator2 extends AbstractDecorator {
public ConcreteDecorator2(Conponent conponent) {
super(conponent);
}
@Override
public int read() {
return conponent.read() + 1;
}
}
客户端:
public static void main(String[] args) {
Conponent conponent1 = new ConcreteConponent1();
Conponent decorator1 = new ConcreteDecorator1(conponent1);
System.out.println("conponent1没有装饰前的值:" + conponent1.read() + ";被decorator1装饰后的值:" + decorator1.read());
Conponent decorator2 = new ConcreteDecorator2(conponent1);
System.out.println("conponent1没有装饰前的值:" + conponent1.read() + ";被decorator2装饰后的值:" + decorator2.read());
}
输出:
conponent1没有装饰前的值:95;被decorator1装饰后的值:94
conponent1没有装饰前的值:95;被decorator2装饰后的值:96
个人觉得,选择装饰者模式还是桥接模式,只需要在定义抽象类的时候问一句,这个抽象类是不是就是这个接口呢,如果是,选择装饰着,如果不是则选择桥接,比如上边桥接的例子,邮件发送消息和短信发送消息相比于紧急消息和普通消息而言,它们其实不是消息而是一种发送方式;这里装饰者举的是java.io包的io流的例子,使用io的read方法,接口Conponent相当于抽象类InputStream,抽象类AbstractDecorator相当于FilterInputStream,这样一来,装饰出来的新流根本上讲还是个流,所以大家使用统一接口后者抽象类
模式 | 抽象类是否持有接口 | 抽象类和接口能否说成是一类东西 |
---|---|---|
桥接 | 持有 | 不能 |
装饰者 | 不持有 | 能 |