Contents
  1. 1. 代理模式
  2. 2. 适配器模式
    1. 2.1. 思路分析:

代理模式

  1. 四种不同的代理模式:分别实现了某一个类某一个方法的代理,某一些类(相同接口)某一个方法的代理、某一些类(相同接口)中所有接口方法的代理、所有类中所有非final方法的代理。

https://www.cnblogs.com/cenyu/p/6289209.html

提供了对目标对象另外的访问方式,即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.

  • 最简单的代理模式:代理类的构造方法里new一个代理类作为成员变量,然后重写代理方法。优点简洁,缺点没有可扩展性

    public class Human {
    public void sleep(){
    System.out.println("i am sleeping");
    }
    }
    public class HumanProxy {
    private Human man=null;
    public HumanProxy(){
    man=new Human();
    }
    public void sleep(){
    System.out.println("i am going to sleep");
    man.sleep();
    System.out.println("i am awake");
    }
    }
    public class Test {
    public static void main(String[] args) {
    HumanProxy proxy=new HumanProxy();
    proxy.sleep();
    }
    }
  • 静态代理模式:实现满足某接口的所有实现类的代理
    实现方法:

  1. 设定一个接口,针对该接口设计一个代理类,来代理所有该接口的实现类
  2. 把接口类作为成员变量,在创建代理接口类时初始化
  3. 重写接口类的代理方法

缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.

下面的例子:AnimalProxy可以代理所有Animal的实现类的sleep方法。根据注入实现类的不同,实现主体方法的不同

public interface Animal {
public void sleep();
}
public class AnimalProxy implements Animal{
private Animal animal;
public AnimalProxy(Animal animal){
this.animal=animal;
}
@Override
public void sleep() {
System.out.println("animal going to sleep");
animal.sleep();
System.out.println("animal awake");
}
}
public class Human implements Animal{
@Override
public void sleep() {
System.out.println("i am human, going to sleep");
}
}
public class Dog implements Animal{
@Override
public void sleep() {
System.out.println("i am dog, going to sleep");
}
}
public class Test {
public static void main(String[] args) {
//Human some=new Human();
Dog some=new Dog();
AnimalProxy proxy=new AnimalProxy(some);
proxy.sleep();
}
}

  • 动态代理模式:利用JDK反射的原理,对委托类的接口所有方法都进行一次性但是相同预处理,缺点在于不灵活
    静态代理可以实现不同的实现方法都要一个个的实现,但是每个预处理可以不一样,也可以一样。如果接口添加新方法的话,则静态代理类要添加新的方法来支持代理。
    动态代理可以实现通用的所有接口方法做出相同的预处理,这样,接口类添加新方法,只要预处理的逻辑没变,则代理类的代码不变。

    public class ProxyFactory {
    //维护一个目标对象
    private Object target;
    public ProxyFactory(Object target){
    this.target=target;
    }
    public Object getProxyInstance(){
    return Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("开始事务2");
    //执行目标对象方法
    Object returnValue = method.invoke(target, args);
    System.out.println("提交事务2");
    return returnValue;
    }
    }
    );
    }
    }
    //测试类
    public static void main(String[] args) {
    Dog target=new Dog();
    Animal proxy= (Animal) new ProxyFactory(target).getProxyInstance();
    proxy.sleep();
    proxy.bark();
    }
  • cglib代理模式:运行期,通过在内存中创建一个工具类Enhancer继承委托类,在对工具类进行预处理,所有的方法都嵌入了代理逻辑,所有满足这种预处理方法的类的方法都可以被代理(final)的方法除外

适配器模式

原理:不兼容的接口之间的桥梁。它让一个类经过适配之后可以实现不兼容接口的功能。适配器不是在详细设计时添加的,而是解决正在服役的项目的问题

思路分析:

MP3播放器只能放MP3类型的歌曲,要让他支持可以播放MP4的话,可以让MP3类继承MP4类,或者把MP4类用成员变量的方式注入到MP3类里面。
MP3继承MP4类的缺点:

  • JAVA单继承,如果继承了MP4类,就不能根据自己业务继承其它类,不能继承
  • 如果要扩展其它的兼容功能,例如FLV格式的文件,继承就不行,不能同时继承FLV和MP4

所以最佳是通过注入的形式,实现支持兼容性功能。同理,如果直接注入MP4类的话,那么如果业务变更,还要支持FLV格式的文件播放的话,则还要注入FLV类,我们希望把这个过程剥离开来。于是有了Adapter,他根据业务需要实例化成业务需要的类,可以是FLV,也可以是MP4,甚至可以同时是FLV和MP4,这样只要注入一个Adapter,就可以灵活应对业务变更了。

Adapter就是未来需求变更的改动类了,Adapter要解决的问题是:提供一个方法,通过参数不同,去调用不同兼容类去实现功能。结构如下

Adapter{
private MP4 mp4=new MP4();
private FLV flv=new FLV();
public void play(String type,String fileName){
if(type.equals("mp4"){
mp4.play(fileName)
}else{
flv.play(fileName)
}
}
}

上面就是一种很好的模式,但是如果我只要放MP4的歌、或者只要放FLV的歌的话,我都会实例化2个播放器,这样有些浪费内存,如果业务上要求有时放MP4有时放FLV的话,上面就是最好的选择,如果业务一次只需要实现一种接口即可的话,可以按照下面来操作

public class MediaAdapter {
Mp4Player mp4;
VlcPlayer vlc;
//构造适配器的时候实例化 代理类
public MediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc") ){
vlc = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
mp4 = new Mp4Player();
}
}
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
vlc.play(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
mp4.play(fileName);
}
}
}

目标类AudioPlayer,注入了mediaAdapter接口,并且根据需求,实例化

public class AudioPlayer{
MediaAdapter mediaAdapter;
public void play(String audioType, String fileName) {
//播放 mp3 音乐文件的内置支持
if(audioType.equalsIgnoreCase("mp3")){
play(fileName);
}
//mediaAdapter 提供了播放其他文件格式的支持
else if(audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else{
System.out.println("Invalid media. "+audioType + " format not supported");
}
}
public void play(String fileName){
System.out.println("Playing mp3 file. Name: "+ fileName);
}
}

客户端现在可以通过适配之后的AudioPlayer,播放不同类型的歌曲了

public class Client {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}

Contents
  1. 1. 代理模式
  2. 2. 适配器模式
    1. 2.1. 思路分析: