适配器模式
适配器模式是指,将一个类的接口转换成客户希望的另外一个接口。Adpter 模式使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作
何时使用?
在软件开发前期,类和方法的命名应该就规范地设计好,在一开始出现不兼容时就应该通过重构来同一接口。通常只有在开发后期或维护期,由于双方都不太容易修改接口是,才应该考虑使用适配器模式。
另一种情况是,在设计系统是,考虑使用第三方开发组件,组件的接口和公司的系统接口不同,又没有必要为了迎合它而改变自己的接口,那么在开发前期也可以考虑采用适配器模式。
模式
Target
(客户期待的接口。目标可以是具体的或抽象类,也可以是接口):
public interface Target {
public void request();
}
Adaptee
(需要适配的类):
public class Adaptee {
public void specificRequest() {
System.out.println("特殊请求");
}
}
Adapter
(通过在内部包装一个 Adaptee
对象,把源接口转换成目标接口):
public class Adapter implements Target {
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
adaptee.specificRequest();
}
}
IO 包中的应用
在 java.io 包中,也使用了适配器模式:
ByteArrayInputStream 继承了 InputStream 接口,而内部封装了一个 byte 数组,它将 byte 数组接口适配成 InputStream 流处理器接口。
FileInputStream 继承了 InputStream 接口,而内部有 FileDescriptor对象的引用,它将 FileDescriptor 的接口适配成 InputStream 流处理器接口。
InputStreamReader 将 InputStream 的接口适配成了 Reader 的接口,虽然它内部并不是使用了 InputStream 的引用,而是通过 StreamDecoder 类。
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
public InputStreamReader(InputStream in, Charset cs) {
super(in);
if (cs == null)
throw new NullPointerException("charset");
sd = StreamDecoder.forInputStreamReader(in, this, cs);
}
public int read() throws IOException {
return sd.read();
}
...
}
装饰器模式
装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
这里的动态和动态代理的动态不同,装饰模式是为已有的功能通过包裹一连串的装饰器来动态添加更多的功能和属性。它的好处是,将类的核心职责和装饰功能区分开,而且去除相关类中重复的装饰逻辑。用户可以有选择地、按顺序地使用装饰功能包装对象。
模式
Component
(定义对象接口,可以给对象动态地添加职责)
interface Component {
void operation();
}
ConcreteComponent
(具体对象,作为被装饰的对象)
class ConcreteComponent implements Component {
public void operation() {
System.out.println("具体对象的操作");
}
}
Decorator
(抽象装饰器类,从外类来扩展 Component)
abstract class Decorator implements Component {
protected Component component;
public void setComponent(Component component) {
this.component = component;
}
public void operation() {
if (component != null) {
component.operation();
}
}
}
ConcreteDecoratorA
(具体的装饰器类,增强属性)
class ConcreteDecoratorA extends Decorator {
private String addedState = "state";
public void operation() {
super.operation();
System.out.println("具体的装饰器类 A 的新增属性为:" + addedState);
}
}
ConcreteDecoratorB
(具体的装饰器类,增强方法)
class ConcreteDecoratorB extends Decorator {
public void operation() {
super.operation();
addedBehavior();
}
private void addedBehavior() {
System.out.println("具体的装饰器类 B 的新增操作");
}
}
客户端
ConcreteComponent c = new ConcreteComponent(); // 被代理的对象
ConcreteDecoratorA a = new ConcreteDecoratorA();
ConcreteDecoratorB b = new ConcreteDecoratorB();
a.setComponent(c);
b.setComponent(a);
b.operation();
/*
具体对象的操作
具体的装饰器类 A 的新增属性为:state
具体的装饰器类 B 的新增操作
*/
代理模式和装饰器模式的区别
代理模式下,代理对象引用的真实对象可以由代理对象构造,用户不需要知道真实对象的存在。当然,用户构造一个真实对象传给代理也是可以的。但代理模式的理念是,代理对象是真实对象的代表。
public interface Greeting {
void sayHello(String name);
}
public class GreetingImpl implements Greeting {
@Override
public void sayHello(String name) {
System.out.println("Hello! " + name);
}
}
public class GreetingProxy implements Greeting {
private Greeting greeting;
public GreetingProxy(Greeting greeting) {
this.greeting = greeting;
}
@Override
public void sayHello(String name) {
before();
greeting.sayHello(name);
}
private void before() {
System.out.println("Before");
}
}
public class Client {
public static void main(String[] args) {
Greeting greeting = new GreetingProxy(new GreetingImpl());
greeting.sayHello("Hello, world!");
}
}
使用场景:
- 隐藏某个类。
- 在代理中进行权限判断来进行不同权限的功能调用。
- 简单扩展某个类的功能。
我们再看一个装饰器模式的实现:
public abstract class GreetingDecorator implements Greeting {
private Greeting greeting;
public GreetingDecorator(Greeting greeting) {
this.greeting = greeting;
}
@Override
public void sayHello(String name) {
greeting.sayHello(name);
}
}
GreetingDecorator 和 GreetingProxy 类看起来很像,但是它并不直接增强 Greeting 对象的功能,而是通过自己的实现类来进行增强。
第一个具体的装饰器 GreetingBefore:
public class GreetingBefore extends GreetingDecorator {
public GreetingBefore(Greeting greeting) {
super(greeting);
}
@Override
public void sayHello(String name) {
before();
super.sayHello(name);
}
private void before() {
System.out.println("Before");
}
}
第二个具体的装饰器 GreetingAfter :
public class GreetingAfter extends GreetingDecorator {
public GreetingAfter(Greeting greeting) {
super(greeting);
}
@Override
public void sayHello(String name) {
super.sayHello(name);
after();
}
private void after() {
System.out.println("After");
}
}
具体装饰器的构造方法调用了父类的构造方法,将实际对象传递进去,而在具体装饰器中,只完成自己的增强工作,其他的交给父类。
可以这样来使用装饰器:
public class ClientDecorator {
public static void main(String[] args) {
Greeting greeting = new GreetingAfter(new GreetingBefore(new GreetingImpl()));
greeting.sayHello("Hello,World!");
}
}
一层包一层地添加了装饰功能,而且包裹的顺序可以交换。这和 JDK 的 IO 包中方法很像。而 IO 包的设计其实也到了装饰模式。
InputStream input = new DataInputStream(new BufferedInputStream(
new FileInputStream("C:/test.exe")));