结构型模式--设计模式详解?

2022-12-14 18:26:00 浏览数 (1)

上篇文章说了,单一职责,接口隔离,里氏替换,依赖倒置,迪米特,开闭原则。

设计模式六大原则

适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

适配器模式:

将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由某个接口不匹配所造成的类的兼容性问题。

类的适配器模式,对象的适配器模式,接口的适配器模式。

类的适配器模式 :可以通过多重继承目标接口和被适配者方法来实现适配。当希望一个类转换满足另一个类的新接口时候,可以使用类适配器创建新类继承原有的类。

对象的适配器模式:使用了不同的方法实现适配,对象适配器使用组合,类的适配器使用继承。当希望将一个对象满足另一个新接口对象时,可以创建wrapper类。

接口的适配器模式:当不需要全部接口实现方法时候,可设计一个抽象类实现接口,并为该接口每个方法提供默认的实现方法,那么该抽象子类可以有选择的覆盖父类某些方法来实现,它使用接口不想使用所有方法的情况。

装饰者模式:

定义:动态的将新功能附加到对象上。增加对象功能扩展性,比继承更有弹性。

装饰者和被装饰者之间必须是一样的类型,也就是共同的超类。因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。根据这个理解,我们可以在任何时候实现新的装饰者增加新的行为。

代理模式:

定义:给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

静态代理:

代码语言:javascript复制
public interface BuyBus {

    void buyBus();
}


public class BuyBusProxy implements BuyBus{

    private BuyService buyService;

    BuyBusProxy(BuyService buyService){
        this.buyService = buyService;
    }

    @Override
    public void buyBus() {
        // 买车前干啥
        buyService.buyBus();
        // 买车后干啥
    }
}

public class BuyService implements BuyBus{

    @Override
    public void buyBus() {
        System.out.println("买车");
    }
}

优点:复合开闭原则对代码扩展的情况下不修改原有的代码。

缺点:每次都需要新增代理类,工作量大,代码多,一旦改变代理类也要改变。

动态代理:

利用jdk的api来实现代理对象的生成,动态的在内存中构建代理对象,代理的类不需要实现接口,但是要求被代理的对象必须有接口。

代码语言:javascript复制
public class DynamicProxyHandler implements InvocationHandler {
    private Object object;

    public DynamicProxyHandler(final Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object object, Method method, Object[] args) throws Throwable {
        System.out.println("执行前");
        Object result = method.invoke(object, args);
        System.out.println("执行后");
        return result;
    }
}


  public static void main(String[] args) {
        BuyServiceImpl buyServiceImpl = new BuyServiceImpl();
        BuyBusService proxyBuy =(BuyBusService) Proxy.newProxyInstance(BuyBusService.class.getClassLoader(),
                new Class[]{BuyBusService.class}, new DynamicProxyHandler(buyServiceImpl));
        proxyBuy.buyBus();
    }

动态代理相对于静态代理,节俭了很多代码,提高了复用性,但一样依赖于接口。

cglib代理

动态生成一个要代理的子类,子类重写要代理类的所有不是final方法,子类中采用方法拦截技术拦截所有父类方法调用,横切逻辑,优于jdk动态代理。

缺点是对final方法无法进行代理。

代码语言:javascript复制
public class CglibProxy implements MethodInterceptor {

    private Object object;
    public Object getInstance(Object object){
        this.object = object;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.object.getClass());
        enhancer.setCallback(this);
        return enhancer;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行前准备");
        Object result = methodProxy.invoke(o,objects);
        System.out.println("执行后准备");
        return result;
    }
}


  public static void main(String[] args) {
        BuyBusService buyBusService = new BuyServiceImpl();
        CglibProxy cglibProxy = new CglibProxy();
        BuyServiceImpl proxyBuy = (BuyServiceImpl)cglibProxy.getInstance(buyBusService);
        proxyBuy.buyBus();
    }

cglib的性能比jdk动态代理性能更好,但是cglib创建对象比jdk创建对象耗时更多,所以单例模式下,无需频繁创建对象用cglib更合适,而且cglib因为动态创建子类,所以final修饰的无法代理。

外观模式

隐藏系统的复杂性,并且向客户端提供一个可以访问的接口。

核心的功能就是门面角色 整合所有子系统角色,方便外部统一访问。

代码语言:javascript复制
public class Fang {
    private Deng deng;
    private Door door;

    public void open(){
        System.out.println("进入房间");
        deng.open();
        door.open();
    }
    public void close(){
        System.out.println("出去房间");
        deng.close();
        door.close();
    }
}

public class Door {
    public void open(){
        System.out.println("开门");
    }
    public void close(){
        System.out.println("关门");
    }
}


public class Deng {

    public void open(){
        System.out.println("开灯");
    }
    public void close(){
        System.out.println("关灯");
    }
}

外观模式优点是访问对于客户端更简洁明了,不需要在乎他内部调用多少服务。

桥接模式

定义:将抽象部分与它的实现部分分离,使他们可以独立变化。

代码语言:javascript复制


public interface Software {
    public void run();
}

public abstract class Phone {
    public abstract void run();
}

public class AppStore implements Software{

    @Override
    public void run() {
        System.out.println("app start run");
    }
}

public class Camera implements Software{

    @Override
    public void run() {
        System.out.println("Camera start run");
    }
}

继承是一种强耦合,通过桥接把他们关联起来,如同弱耦合,从这里可以看出聚合是一种比继承要弱的关系,两个都可以独立进行变化,不会相互影响。

当两个类存在独立的变化维度,且两个类都需要独立扩展的时候。

组合模式

又叫做部分-整体模式,将对象组合成树状的层次结构模式,表示部分-整体的关系,使用户对单个对象和组合对象具有一定访问一致性。

模糊了简单元素与复杂元素的概念,客户端可以处理简单元素一样来处理复杂元素,从而使客户程序与复杂元素内部解耦。

缺点就是客户端需要花费更多的时间来处理层次关系。

享元模式

通过共享的方式高效的支持大量细颗粒对象。

当有大对象的时候,可能会造成内存溢出,我们把其中共同部分抽象出来,如果有相同的业务请求,直接返回内存已有对象。

用唯一标识码,如果在内存中有,则返回唯一标识码标识的对象。hashmap,java中的String如果有则返回,没有则创建一个字符串保存在字符串缓存池中

0 人点赞