结构性模式
适配器模式(Adapter)
- 将一个类的接口转换成客户端的另外一个接口。Adapter模式使得原来本由于接口不兼容而不能在一起工作的哪些类可以在一起工作
- 通过包装一个不适配的对象,把原接口转换成目标对象
例子:电脑,网线,适配器
- 电脑
//客户端类:要连上网线
public class Computer {
public void getNet(Adapter adapter){
//找一个转接头
adapter.handleResquest();
}
}
- 网线
//被适配的类:网线
public class NetLine {
public void request(){
System.out.println("连接网线上网");
}
}
- 适配器
//接口转换器的接口
public interface Adapter {
//处理请求
public void handleResquest();
}
//适配器
public class MacAdapter implements Adapter {
/**
* 使用组合的,不推荐使用继承
* 这种把对象注入进来的,叫对象适配器
* 可以适配一个适配者的子类,由于适配者和适配器之间是关联关系,根据"里氏代换原则"适配者的子类也可以通过该适配器进行适配
* 还可以使用继承的方式,但是java不支持多继承,不推荐使用
*/ private NetLine netLine;
public MacAdapter(NetLine netLine) {
this.netLine = netLine;
}
public void handleResquest() {
netLine.request();
}
}
- 测试
class Test {
public static void main(String[] args) throws CloneNotSupportedException {
//上网:电脑+网线+适配器
Computer computer=new Computer();
NetLine netLine=new NetLine();
Adapter adapter=new MacAdapter(netLine);
computer.getNet(adapter);
}
}
桥接模式(bridge)
- 将抽象部分与他的实现部分分离,使他们都独立的变化
- 它是一种对象结构型模式吗,又称为柄体模式(Handle and Body)或接口模式(Interfce)
- 好处:
- 桥接模式有点类似于多继承方案,但是多继承方案违背了单一职责原则复用性比较差
- 桥接模式极大的减少了子类的个数,降低管理和维护成本
- 提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有的系统。符合开闭原则
- 缺点:
- 增加系统的理解与设计难度,要对抽象进行编程
- 桥接模式要求正确识别出系统中两个独立变化的维度,使用范围有一定的局限性
例子:电脑和品牌
- 品牌类
//品牌
public interface Brand {
void info();
}
public class Apple implements Brand {
public void info() {
System.out.println("苹果");
}
}
public class Lenove implements Brand{
public void info() {
System.out.println("联想");
}
}
- 电脑:使用组合的方式把品牌组合进电脑
//电脑抽象类
public class Computer {
//组合品牌
protected Brand brand;
public Computer(Brand brand) {
this.brand = brand;
}
public void info(){
brand.info(); //自带品牌
}
}
//台式机类
public class Desktop extends Computer{
public Desktop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.println("台式机");
}
}
//笔记本
public class Laptop extends Computer{
public Laptop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.println("笔记本");
}
}
- 测试类
class Test {
public static void main(String[] args) throws CloneNotSupportedException {
//电脑
Computer computer= new Laptop(new Apple());
computer.info();
}
}
代理模式(proxy)
- 分类:
- 静态代理
- 动态代理
静态代理
- 角色
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作
- 客户角色:访问代理对象的人
== 例子:租房子==
//租房接口
public interface Rent {
void rent();
}
//房东
public class Host implements Rent {
public void rent() {
System.out.println("房东要出租房子");
}
}
//中介
public class Proxy implements Rent {
private Host host;
public Proxy(Host host) {
this.host = host;
}
public void rent() {
System.out.println("代理找房子");
host.rent();
this.showHose();
this.finese();
}
private void showHose(){
System.out.println("中介带你看房");
}
private void finese(){
System.out.println("签合同");
}
}
//客户
public class Client {
public static void main(String[] args) {
Host host =new Host();
Proxy proxy=new Proxy(host);
proxy.rent();
}
}
- 代理模式的好处:
- 可以使用真实角色的操作更加纯粹,不用去关注一些公共业务
- 公共业务也就交给了代理角色!实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
- 缺点:
- 一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率会变低
- 动态代理好处:
- 一个动态代理代理的是一类接口,一般就是对应的一类业务
- 一个动态代理可以代理多个类,只要实现了同一个接口即可
动态代理
-
角色:动态代理和静态代理的角色是一样
-
动态代理的代理类是动态生成的
-
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口:JDK动态代理
- 基于类:cgLib
- Java字节码实现:javasist
-
了解两个类:
- Proxy:代理
- InvocationHandler:调用处理程序
InvocationHandler是由代理实例的调用处理程序实现的接口。
每个代理实例都有一个关联的调用处理程序。 在代理实例上调用方法时,方法调用将被编码并调度到其调用处理程序的invoke方法。
- 实现一个万能代理类生成类:
//使用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成代理对象
public Object getProxy(){
return Proxy.newProxyInstance(
this.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
//处理代理实类,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制实现
Object result = method.invoke(target, args);
return result;
}
}
- 测试使用:Host是一个继承Rent接口的实现类,Rent是一个接口
public class Client {
public static void main(String[] args) {
//真实角色
Host host=new Host();
//代理角色:动态创建
ProxyInvocationHandler handler = new ProxyInvocationHandler();
//通过调用程序处理角色,来创建对象
handler.setTarget(host);
Rent proxy = (Rent)handler.getProxy(); //这里的proxy是动态生成的
proxy.rent();
}
}