结构型设计模式
结构型设计模式是从程序的结构上解决模块之间的耦合问题的,它包括设配器模式、代理模式、装饰模式、外观模式、桥接模式、组合模式和享元模式。
代理模式(委托模式)
定义: 为其他对象提供一种代理以控制对这个对象的访问。
结构流程:
Client --> Subject <-- (RealSubject 和 Proxy)
RealSubject <-- Proxy
- Subject: 抽象主题类,声明真实主题与代理的共同接口方法。
- RealSubject:真实主题类,代理类所代表的真实主题。客户端通过代理类间接地调用真实主题类的方法。
- Proxy:代理类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行。
- Client: 客户端类。
静态代理的实现
(1)抽象主题类
public interface IShop {
void buy();
}
(2)真实主题类
public class Real implements IShop {
@Override
public void buy() {
System.out.println("购买");
}
}
(3)代理类
public class ProxyClass implements IShop {
private IShop iShop;
public ProxyClass(IShop iShop){
this.iShop = iShop;
}
@Override
public void buy() {
iShop.buy();
}
}
(4)客户端类
public class Client {
public static void main(String[] args){
IShop iShop = new Real();
ProxyClass proxy = new ProxyClass(iShop);
proxy.buy();
}
}
动态代理模式
这里是根据上述静态代理模式,进行修改的。
(1) 创建动态代理模式
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(object, args);
if (method.getName().equals("buy")){
System.out.println("买东西");
}
return result;
}
}
(2)客户端
public class Client {
public static void main(String[] args){
//动态代理
IShop iShop = new Real();
//创建动态代理模式
DynamicProxy dynamicProxy = new DynamicProxy(iShop);
//创建Real() 的 ClassLoader (类加载器)
ClassLoader classLoader = iShop.getClass().getClassLoader();
//动态创建代理类
IShop purchasing = (IShop)Proxy.newProxyInstance(classLoader, new Class[]{IShop.class}, dynamicProxy);
purchasing.buy();
}
}
可适用的范围:
- 远程代理: 为一个对象在不同的地址空间提供局部代表,这样系统可以将 Server 部分的实现隐藏。
- 虚拟代理:使用一个代理对象表示一个十分耗费资源的对象并在真正需要时才创建。
- 安全代理:用来控制真实对象访问时的权限。一般用于真实对象有不同的访问权限时。
- 智能指引:当调用真实的对象时,代理处理另外一些事,比如计算真实对象的引用计数,当该对象没有引用时,可以自动释放它;或者访问一个实际对象时,检查是否已经能够锁定它,以确保其他对象不能改变它。
优点:
- 真实主题类就是实现实际的业务逻辑,不用关心其他非本职的工作。
- 真实主题类随时都会发生变化;但是因为它实现了公共的接口,所有代理类可以不做任何修改就能够使用。
装饰模式
定义:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
结构流程:
ConcreteComponent --> Component <-- Decorator <-- ConcreteDecorator
- Component: 抽象组件,可以是接口或时抽象类,被装饰的最原始的对象。
- ConcreteComponent: 组件具体实现类。Component 的具体实现类,被装饰的具体对象。
- Decorator: 抽象装饰者,从外类来拓展 Component 类的功能,但对于 Component 来说无须知道 Decorator 的存在。在它的属性中必然有一个 private 变量指向 Component 抽象组件。
- ConcreteDecorator: 装饰者的具体实现类。
(1)抽象组件
public abstract class Swordsman {
public abstract void attackMagic();
}
(2)组件具体实现类
public class People extends Swordsman {
@Override
public void attackMagic() {
System.out.println("会降龙十八掌第一式");
}
}
(3)抽象装饰者
public abstract class Master extends Swordsman {
private Swordsman swordsman;
public Master(Swordsman swordsman){
this.swordsman = swordsman;
}
@Override
public void attackMagic() {
swordsman.attackMagic();
}
}
(4)抽象装饰者
public class DaXia extends Master {
public DaXia(Swordsman swordsman) {
super(swordsman);
}
public void teachAttackMagic(){
System.out.println("大侠教了降龙十八掌第二式");
System.out.println("会降龙十八掌第二式");
}
@Override
public void attackMagic() {
super.attackMagic();
teachAttackMagic();
}
}
public class DaXia2 extends Master {
public DaXia2(Swordsman swordsman) {
super(swordsman);
}
public void teachAttackMagic(){
System.out.println("大侠教了降龙十八掌第三式");
System.out.println("会降龙十八掌第三式");
}
@Override
public void attackMagic() {
super.attackMagic();
teachAttackMagic();
}
}
(5)客户端
public class Client {
public static void main(String[] args){
People people = new People();
DaXia daXia = new DaXia(people);
daXia.attackMagic();
DaXia2 daXia2 = new DaXia2(people);
daXia2.attackMagic();
}
}
使用场景:
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 需要动态地给一个对象增加功能,这些功能可以动态地撤销。
- 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
优点:
- 通过组合而非继承的方式,动态地扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
- 有效避免了使用继承的方式扩展对象功能而带来的灵活性差、子类无限制扩张的问题。
- 具体组件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体组件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合 “ 开放封闭原则 ”
缺点:
- 因为所有对象均继承 Component ,所以如果 Component 内部结构发生变化,则不可避免地影响所以子类(装饰者或被装饰者)。如果基类改变,则势必影响对象的内部。
- 比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难。
- 装饰层数不能过多,否则会影响效率。