美文网首页
结构型模式

结构型模式

作者: engineer_tang | 来源:发表于2020-07-22 19:14 被阅读0次

简介

将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式。
结构型模式分为:代理模式、适配器模式、装饰模式、桥接模式、外观模式、享元模式、组合模式

结构型模式分类

(1) 代理模式
说明:给某对象提供一个代理以控制对该对象的访问。访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
优点:
在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
代理对象可以扩展目标对象的功能;
将客户端与目标对象分离,降低了系统的耦合度;

缺点:
在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
增加了系统的复杂度;
1 ) 静态代理实现
目标接口代码

package com.threadtest.designpattern;

public interface Subject {

    void request();
}

目标接口实现类代码

package com.threadtest.designpattern;

public class RealSubject implements Subject {

    @Override
    public void request() {
        System.out.println("执行了目标类请求!");
    }
}

代理类实现代码

package com.threadtest.designpattern;

public class SubjectProxy implements Subject {

    private RealSubject realSubject;

    @Override
    public void request() {
        if(realSubject == null) {
            realSubject = new RealSubject();
        }
        preRequest();
        realSubject.request();
        postRequest();
    }

    private void preRequest() {
        System.out.println("执行目标对象前执行的业务!");
    }

    public void postRequest() {
        System.out.println("执行目标对象后执行的业务!");
    }
}

代理执行源码

package com.threadtest.designpattern;

public class ProxyTest {

    public static void main(String[] args) {
        SubjectProxy proxy = new SubjectProxy();
        proxy.request();
    }
}

2 ) 动态代理实现
a. JDK动态代理

package com.threadtest.designpattern;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class SubjectInvocationHandler implements InvocationHandler {

    private RealSubject realSubject;

    public SubjectInvocationHandler(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行目标代码前业务执行...!");
        method.invoke(realSubject, args);
        System.out.println("执行目标代码后业务执行...!");
        return null;
    }
}

代理执行源码

package com.threadtest.designpattern;

import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String[] args) {
        Subject subject = (Subject) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class[]{Subject.class}, new SubjectInvocationHandler(new RealSubject()));
        subject.request("李白");
        subject.request2();
    }
}

b. Cglib动态代理
向pom.xml引入cglib包

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

目标类源码

package com.design;

public class RealSubject {

    public void request(String name) {
        System.out.println(name + " 执行了目标类请求!");
    }


    public void request2() {
        System.out.println("执行了目标类请求2!");
    }
}

定义拦截器源码

package com.design;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class SubjectMethodInterceptor implements MethodInterceptor {

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行目标类前的业务!");
        Object result = methodProxy.invokeSuper(o, objects);
        return result;
    }
}

定义动态代理工厂

package com.design;

import net.sf.cglib.proxy.Enhancer;

public class ProxyFactory {

    public static Object getCglibDynProxy(Object target) {

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new SubjectMethodInterceptor());
        return enhancer.create();
    }
}

定义具体执行类

package com.design;

public class ProxyTest {

    public static void main(String[] args) {
        RealSubject realSubject = (RealSubject) ProxyFactory.getCglibDynProxy(new RealSubject());
        realSubject.request("陶渊明");
        realSubject.request2();
    }
}

(2) 适配器模式
说明:将一个类的接口转换成客户希望的另外一个接口,使不兼容的接口在一起工作。
1 ) 类适配器模式
目标接口源码

package com.design;

public interface Bird {

    void sayBirdLanguage();
}

适配者类源码

package com.design;

public class Pig {

    public void sayPigLanguage() {
        System.out.println("我是猪,所以我说猪语!");
    }
}

适配器类源码

package com.design;

public class ClassLanguageAdapter extends Pig implements Bird {

    public void sayBirdLanguage() {
        System.out.println("转化为鸟语!");
        sayPigLanguage();
    }
}

适配器执行源码

package com.design;

public class LanguageTest {

    public static void main(String[] args) {
        Bird bird = new ClassLanguageAdapter();
        bird.sayBirdLanguage();
    }
}

2 ) 对象适配器模式
适配器源码

package com.design;

public class ObjectLanguageAdapter implements Bird {

    private Pig pig;

    public ObjectLanguageAdapter(Pig pig) {
        this.pig = pig;
    }

    public void sayBirdLanguage() {
        System.out.println("转化为鸟语!");
        pig.sayPigLanguage();
    }
}

配置器执行代码

package com.design;

public class LanguageTest {

    public static void main(String[] args) {
        Bird bird = new ObjectLanguageAdapter(new Pig());
        bird.sayBirdLanguage();
    }
}

(3) 桥接模式
说明:用组合关系将抽象与实现分离,使它们可以独立变化。
优点:
由于抽象与实现分离,所以扩展能力强;
其实现细节对客户透明。

缺点
由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,这增加了系统的理解与设计难度。

实现化角色源码

package com.design;

public interface Fruit {

    void taste();
}

具体实现化角色源码

package com.design;

public class Apple implements Fruit {

    public void taste() {
        System.out.println("我的味道有点苦涩!");
    }
}

抽象化角色源码

package com.design;

public abstract class AbstractShop {

    protected Fruit fruit;

    public AbstractShop(Fruit fruit) {
        this.fruit = fruit;
    }

    protected abstract void sale();
}

扩展抽象化角色源码

package com.design;

public class AppleShop extends AbstractShop {

    public AppleShop(Fruit fruit) {
        super(fruit);
    }

    protected void sale() {
        System.out.println("我们这里卖的是苹果!");
        fruit.taste();
    }
}

(4) 装饰模式
说明:在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。
优点:
采用装饰模式扩展对象的功能比采用继承方式更加灵活。
可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。

缺点
装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。
抽象构建角色源码

package com.design;

public interface Person {

    void work();
}

具体构建角色源码

package com.design;

public class Woman implements Person {

    public void work() {
        System.out.println("我的工作是文员!");
    }
}

抽象装饰角色源码

package com.design;

public class DecoratorPerson implements Person {

    private Person person;

    public DecoratorPerson(Person person) {
        this.person = person;
    }


    public void work() {
        person.work();
    }
}

具体装饰角色源码

package com.design;

public class DecoratorPersonTraffic extends DecoratorPerson {

    public DecoratorPersonTraffic(Person person) {
        super(person);
    }

    public void work() {
        super.work();
        backHome();
    }

    public void backHome() {
        System.out.println("下班回家!");
    }
}

装饰器测试执行源码

package com.design;

public class DecoratorTest {

    public static void main(String[] args) {
        Person person = new Woman();
        person.work();
        Person person1 = new DecoratorPersonTraffic(person);
        person1.work();
    }
}

(5) 外观模式
说明:通过为多个复杂的子系统提供一个一致的统一的接口,降低程序复杂度,提高代码可维护性。
优点
降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类。
对客户屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易。
降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程,因为编译一个子系统不会影响其他的子系统,也不会影响外观对象。
缺点
不能很好地限制客户使用子系统类。
增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
外观角色源码

package com.design;

public class LunchPlan {

    private FruitNeed fruitNeed = new FruitNeed();
    private MeatNeed meatNeed = new MeatNeed();
    private TeaNeed teaNeed = new TeaNeed();

    public void eating() {
        fruitNeed.eat();
        meatNeed.taste();
        teaNeed.drink();
    }
}

子系统角色源码

package com.design;

public class FruitNeed {

    public void eat() {
        System.out.println("用餐时需要吃水果!");
    }
}

package com.design;

public class MeatNeed {

    public void taste() {
        System.out.println("用餐时,需要品尝牛肉的味道!");
    }
}

package com.design;

public class TeaNeed {

    public void drink() {
        System.out.println("用晚餐,还需要喝点奶茶!");
    }
}

外观执行源码

package com.design;

public class FacadeTest {

    public static void main(String[] args) {
        LunchPlan lunchPlan = new LunchPlan();
        lunchPlan.eating();
    }
}

(6) 享元模式
说明:通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销。
优点
相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。

缺点:
为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。
读取享元模式的外部状态会使得运行时间稍微变长。
抽象享元角色源码

package com.design;

public interface Transport {

    public void operate(UnSharedCustomer unSharedCustomer);
}

具体享元角色源码

package com.design;

public class Airplane implements Transport {

    private String basicInfo;

    public Airplane(String info) {
        this.basicInfo = info;
    }

    public void operate(UnSharedCustomer unSharedCustomer) {
        System.out.println("我是飞机,我已经在运营了!");
        if(unSharedCustomer.availuableUse()) {
            System.out.println("登机成功!");
            System.out.println(String.format("乘客信息, 姓名: %s, 年龄: %s", unSharedCustomer.getUserName(), unSharedCustomer.getAge()));
        } else {
            System.out.println("未满18岁不能登机!");
        }

    }
}

非享元角色源码

package com.design;

public class CustomerInfo implements UnSharedCustomer {

    private String userName;

    private int age;

    public CustomerInfo(String userName, int age) {
        this.userName = userName;
        this.age = age;
    }

    @Override
    public String getUserName() {
        return userName;
    }

    @Override
    public int getAge() {
        return age;
    }

    @Override
    public boolean availuableUse() {
        if(age >= 18) {
            return true;
        }
        return false;
    }
}

享元工厂角色源码

package com.design;

import java.util.HashMap;
import java.util.Map;

public class TransportFactory {

    private TransportFactory(){}

    private static final TransportFactory factory = new TransportFactory();

    public final Map<String, Airplane> transportMap = new HashMap<>();

    public static Transport getTransport(String name) {
        Airplane airplane = factory.transportMap.get(name);
        if(airplane == null) {
            airplane = new Airplane(name);
            factory.transportMap.put(name, airplane);
        }
        return airplane;
    }
}

享元执行源码

package com.design;

public class FlyweightTest {

    public static void main(String[] args) {
        Transport transport = TransportFactory.getTransport("hb546333");
        UnSharedCustomer unSharedCustomer = new CustomerInfo("黎明", 52);
        UnSharedCustomer unSharedCustomer1 = new CustomerInfo("李白", 14);
        transport.operate(unSharedCustomer);
        transport.operate(unSharedCustomer1);
    }
}

(7) 组合模式

相关文章

  • PHP常用设计模式

    # 创建型 单例模式 工厂模式 工厂抽象模式 原型模式 建造者模式 # 结构型 # 行为型 # 3.注册模式 # ...

  • 23种设计模式总结二

    23 种经典设计模式共分为 3 种类型,分别是创建型、结构型和行为型。 结构型设计模式 结构型模式就是一些类或对象...

  • 设计模式(行为型)-- 观察者模式

    我们常把 23 种经典的设计模式分为三类:创建型、结构型、行为型。创建型设计模式主要解决“对象的创建”问题,结构型...

  • iOS 开发的23种设计模式简介

    设计模式主要分三个类型:创建型、结构型和行为型。 其中创建型有: 行为型有: 结构型有:

  • 23种设计模式总结一

    23 种经典设计模式共分为 3 种类型,分别是创建型、结构型和行为型。 一、创建型设计模式 创建型设计模式包括:单...

  • 设计模式简单总结(待完善)

    设计模式简单总结 设计模式可以分为:创建型,结构型,行为型三种模式。 1 创建型模式 1.1 单例模式 用来指定某...

  • D31组织结构模式

    海星型组织:用共识建立起来的组织结构模式,就是海星型组织。 例如区块链,代币,智能合约等结构模式都属于这类模式,他...

  • Nodejs实现23种设计模式-1.简单工厂模式

    Nodejs实现24种设计模式--简单工厂模式 导语:24种设计模式,分为三大类,创建型、结构型和行为型。这些模式...

  • 设计模式归纳

    一、设计模式的分类 23 种经典的设计模式分为三类:创建型、结构型、行为型。 1.创建型设计模式主要解决“对象的创...

  • 设计模式之工厂模式

    设计模式中主要分为三大类:创建型、结构型、行为型 工厂模式属于创建型,顾名思义,创建型模式关注对象的创建过程,它将...

网友评论

      本文标题:结构型模式

      本文链接:https://www.haomeiwen.com/subject/llbtlktx.html