这篇文章主要讲解了“如何使用结构型模式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用结构型模式”吧!
所谓适配器模式,就是把一个类的结构转换成另外一个类的接口。使得原本由于接口不兼容而不能工作的类都能够一起工作。
在生活中比较常见的就是当我们想连接显示器的时候,vga需要转成hdmi,还有电源适配,比如可能需要220v的充电头,但是只有110v的充电头,那么就需要将220v的充电头适配成110v的充电头。
Adaptee:
需要适配的就代码,旧接口
Adapter:
将调用转发给Adaptee
的适配器类
Target:
支持的新接口
Target
public interface Target { void output110v(); }
Adaptee
public class Adaptee { public void output220v() { System.out.println("输出电压"); } }
Adapter
public class Adapter extends Adaptee implements Target { @Override public void output110v() { this.output220v(); } }
这里需要注意的是Adapter
是继承了源类而实现了目标类
Client
public class Client { public static void main(String[] args) { Target target = new Adapter(); target.output110v(); } }
虽然我们是使用了output110v
的充电头,但是经过Adapter后,最终通过this.output220v()
会调用output220v
的充电头,这就是把output220v
适配成了output110v
。
其实说得这么高大上,其实就是Adaptor
的实现方式不同,类适配器模式采用继承了源类(也就是需要适配的类)实现了目标类。
这样就存在一个问题,当我们需要适配多个类的时候就会出现问题,因为java中是允许实现多个接口,但是只能继承一个类。
为了解决这个问题,我们可以把需要适配的类作为Adapter
的成员变量,然后通过构造函数进行适配
public class NewAdapter implements Target{ Adaptee adaptee; public NewAdapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void output110v() { adaptee.output220v(); } }
代理模式也算是比较常用的设计模式之一,大家接触最多的spring aop,就是采用动态代理模式来完成的。代理模式可以分为普通代理模式,强制代理模式,动态代理模式,也是本文着重讲解的,当然还有其代理模式。
先来用一段代码来体会代理模式,场景是玩家打游戏。
Subject:
共同接口,客户端使用的现有接口
RealSubject:
真实对象的类
ProxySubject:
代理对象类
通过上面的例子,相信对大家都对代理模式有点感觉了,但是好像又不那么恰当,上面的测试类种,还是需要新建一个player,这就相当于什么,相当于我们是在手机上登录了游戏,然后再把手机给代练者代练。而事实上,经常是把账号密码给代练即可。
这就引出了普通代理模式,客户端不能访问真实角色,只能访问代理角色,我们能够知道代理的存在。
Subject
public interface SubjectNormalGamePlayer { public void login(); public void upgrade(); public void matches(); }
RealSubject
public class RealSubjectNormalPlayerImpl implements SubjectNormalGamePlayer { private String name; private String password; public RealSubjectNormalPlayerImpl(String name, String password) { this.name = name; this.password = password; } @Override public void login() { if(name.equals("cutey") && password.equals("123456")) { System.out.println(name + "登录成功"); } } @Override public void upgrade() { System.out.println(name + "升级"); } @Override public void matches() { System.out.println(name + "打排位赛"); } }
ProxySubject
public class ProxySubjectNormalPlayerImpl implements SubjectNormalGamePlayer { SubjectNormalGamePlayer gamePlayer; //注意这里的区别,我们是拿账号和密码去登录真实角色 //并不是直接拿真实角色的手机来打 public ProxySubjectNormalPlayerImpl(String name, String password) { gamePlayer = new RealSubjectNormalPlayerImpl(name, password); } @Override public void login() { System.out.print("代练:"); gamePlayer.login(); } @Override public void upgrade() { System.out.print("代练:"); gamePlayer.upgrade(); } @Override public void matches() { System.out.print("代练:"); gamePlayer.matches(); } }
Client
public class Client { public static void main(String[] args) { //通过测试类也很明显区别,不必要显示构造真实角色类 SubjectNormalGamePlayer proxy = new ProxySubjectNormalPlayerImpl("cutey", "123456"); proxy.login(); proxy.upgrade(); proxy.matches(); } }
普通代理呢是去找到一个代理对象帮打,但是强制代理呢,主要是体现在“强制”,角色类会指定一个代理,其它方式找来的代理不能帮我打,一定要用我指定的代理才行。
Subject
和普通代理模式大部分代码一样,不同的是加了一个强制指定代理对象。
public interface SubjectForceGamePlayer { //省略登录、升级和打排位等方法 //强制指定代理对象 public SubjectForceGamePlayer getForceProxy(); }
RealSubject
public class ForceGamePlayerImpl implements IForceGamePlayer { private String name; private String password; private IForceGamePlayer proxy = null; //指定需要谁来代理 public ForceGamePlayerImpl(String name, String password) { this.name = name; this.password = password; } @Override public IForceGamePlayer getForceProxy() { //强制指定代理类,并且只有这样才能给proxy赋值 proxy = new ForceProxyGamePlayerImpl(this); return proxy; } @Override public void login() { //只要不是自己指定的proxy,其它方式proxy肯定是null if(proxy != null) { if(name.equals("imperfect") && password.equals("123456")) { System.out.println(name + "登录成功"); } } else { System.out.println("需要代理"); } } @Override public void upgrade() { if(proxy != null) { System.out.println(name + "升级"); } else { System.out.println("需要代理"); } } @Override public void matches() { if(proxy != null) { System.out.println(name + "打排位赛"); } else { System.out.println("需要代理"); } } }
ProxySubject
public class ProxySubjectForcePlayerImpl implements SubjectForceGamePlayer { private SubjectForceGamePlayer gamePlayer; //接收被代理对象的指定 public ProxySubjectForcePlayerImpl(SubjectForceGamePlayer gamePlayer) { this.gamePlayer = gamePlayer; } //省略登录、升级和打比赛的方法 //没有代理对象,暂时返回自己 @Override public SubjectForceGamePlayer getForceProxy() { return this; } }
Client
public class Client { public static void main(String[] args) { wrongProxy1(); wrongProxy2(); correctProxy(); } public static void correctProxy() { SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456"); //你这个代理必须是我指定的,并且强制要有 SubjectForceGamePlayer proxy = player.getForceProxy(); proxy.login(); proxy.upgrade(); proxy.matches(); } public static void wrongProxy1() { SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456"); SubjectForceGamePlayer proxy = new ProxySubjectForcePlayerImpl(player); proxy.login(); proxy.upgrade(); proxy.matches(); } public static void wrongProxy2() { SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456"); player.login(); player.upgrade(); player.matches(); } }
这个应该是代理模式中用的比较多的,也是我觉得最需要各位小伙伴理解并且掌握的。所谓动态代理是指,不用在编译器指定为谁代理,而是在运行期再获得被代理的对象并且执行代理的方法。
下面将要讲的例子是利用jdk中提供的InvocationHandler和Proxy类
Subject
、RealSubject
都和普通代理模式一样
ProxySubject
我们不知道要给谁代理,所以要用到的是继承InvocationHandler类
public class ProxySubjectDynamicPlayerImpl implements InvocationHandler { Class cls = null; //要代理的类 Object obj = null; //需要代理的对象 //指定需要代理的对象 public ProxySubjectDynamicPlayerImpl(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //调用代理对象的方法 Object result = method.invoke(this.obj, args); if(method.getName().equalsIgnoreCase("login")) { System.out.println("异地登陆提醒:有人登录我的账户"); } return result; } }
Client
public class Client { public static void main(String[] args) { SubjectDynamicPlayer player = new RealSubjectDynamicPlayerImpl("imperfect", "123456"); //把需要代理的信息交给handler,还记得invoke方法吗 //在invoke方法中已经实现了被代理对象的方法 InvocationHandler handler = new ProxySubjectDynamicPlayerImpl(player); //获取被代理类的类加载属性 ClassLoader cl = player.getClass().getClassLoader(); //获取被代理类的接口 Class[] interfaces = player.getClass().getInterfaces(); //把上述的三个信息交给Proxy创建出一个代理类 SubjectDynamicPlayer proxy = (SubjectDynamicPlayer) Proxy.newProxyInstance(cl, interfaces, handler); proxy.login(); proxy.upgrade(); proxy.matches(); } }
在编译时我们是完全不知道给谁代理,一切都是在运行时才知道,这就是“动态”
装饰模式就是动态地给一个对象添加一些恩爱的职责,就增加功能来说,装饰模式比生成子类更为灵活。
无论干什么,最重要的都是扬长避短,对于卖手机也是如此,肯定是把卖点详细地介绍,而对于缺点能不提就不提。
Component:
定义一个对象的接口,可以给这些对象动态地添加职责
ConcreteComponent:
具体的对象
Decorator:
装饰抽象类,继承了Component,从外类来扩展Component
ConcentrateDecorator:
具体的装饰类
Component
public abstract class ComponentMobile { //产品名字 private String name; //省略get,set,tostring方法 public abstract void showDetails(); public abstract void onSale(String userName); }
Concentrate Component
public class ConcreteComponentOnePlus extends ComponentMobile { public ConcreteComponentOnePlus(String name) { super(name); } @Override public void showDetails() { System.out.println("处理器:骁龙888 \r\n拍照:哈苏专业模式 \r\n屏幕:2k+120hz 柔性屏 \r\n充电:65w快充"); } @Override public void onSale(String userName) { System.out.println(userName + "购买了" + getName()); } }
Decorator
public abstract class Decorator extends ComponentMobile { //把要装饰的手机拿给我 private ComponentMobile mobile; public Decorator(String name, ComponentMobile mobile) { super(name); this.mobile = mobile; } //细节还是要展示的 //只不过怎么展示呢,子类可以加以修饰 public void showDetails() { mobile.showDetails(); } //手机也是要出售的 public void onSale(String name) { mobile.onSale(name); } }
注意,我们手机的细节还是要展示的,不能说做的不好就不说出来,欺骗消费者。能把你认出来叫化妆,不能把你认出来叫整容,我们讲的是装饰模式,不是整容模式。
Concrete Decorator
public class ConcreteDecoratorSystem extends Decorator { public ConcreteDecoratorSystem(String name, ComponentMobile mobile) { super(name, mobile); } //装饰系统 public void decorateScreen() { System.out.println("出厂配备了ColorOS,其它型号的手机也会逐步适配"); } @Override public void showDetails() { //想先介绍了系统,再说其他参数 decorateScreen(); super.showDetails(); } }
public class ConcreteDecoratorPrice extends Decorator { public ConcreteDecoratorPrice(String name, ComponentMobile mobile) { super(name, mobile); } //公布价格 public void decoratePrice() { System.out.println("8 + 128:4999"); System.out.println("8 + 256: 5499"); } @Override public void showDetails() { super.showDetails(); //介绍完其它的后,公布性价比较高的价格 decoratePrice(); } }
Client
public class Client { public static void main(String[] args) { //手机发布会,原产品 ComponentMobile mobile = new ConcreteComponentOnePlus("OnePlus 9 Pro"); //装饰下系统 mobile = new ConcreteDecoratorSystem(mobile.getName(), mobile); //装饰下价格 mobile = new ConcreteDecoratorPrice(mobile.getName(), mobile); mobile.showDetails(); //用户一看,诶,不错不错,买了 mobile.onSale("cutey"); } }
感谢各位的阅读,以上就是“如何使用结构型模式”的内容了,经过本文的学习后,相信大家对如何使用结构型模式这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。