结构型设计模式在公司项目中的运用实践

简介: 结构型设计模式在公司项目中的运用实践

关于设计模式的一些实战总结 -- 常见的结构型设计模式


在设计模式里面,有一种叫做适配器的设计模式 Adapter Design Pattern ,这类适配器模式通常应用于做不同接口之间的适配和调整,常见的应用场景例如:


对一些不同实现的接口做统一整合,对一些接口的设计“缺陷”做一定的补救措施。



举个栗子来说,假设某个业务场景里面的遇到了一个人脸识别的功能:


公司内部接入了多个第三方的认证接口,具体的接口设计如下:


public interface IFaceRecognitionService {
    /**
     * 人脸识别
     *
     * @param userId
     * @return
     */
    Boolean recognition(Integer userId);
}


对应的人脸认证接口实现如下:


public class AFaceRecognitionService implements IFaceRecognitionService {
    @Override
    public Boolean recognition(Integer userId) {
        System.out.println("this is AliFaceRecognitionService");
        return true;
    }
}
public class BFaceRecognitionService implements IFaceRecognitionService {
    @Override
    public Boolean recognition(Integer userId) {
        System.out.println("this is B FaceRecognitionService");
        return true;
    }
}


然后此时我们就有两类的认证接口,假设后边的业务愈发扩展,接入的第三方接口越来越多,这时候可以设计出一个灵活的适配器来进行代码的兼容:


public class FaceRecognitionAdaptorService implements IFaceRecognitionService {
    private IFaceRecognitionService faceRecognitionService;
    public FaceRecognitionAdaptorService(IFaceRecognitionService faceRecognitionService){
        this.faceRecognitionService = faceRecognitionService;
    }
    public FaceRecognitionAdaptorService(){
    }
    public IFaceRecognitionService select(int type){
        if(type==1){
            this.faceRecognitionService = new AFaceRecognitionService();
        }else{
            this.faceRecognitionService = new BFaceRecognitionService();
        }
        return this.faceRecognitionService;
    }
    @Override
    public Boolean recognition(Integer userId) {
        return faceRecognitionService.recognition(userId);
    }
    public static void main(String[] args) {
        FaceRecognitionAdaptorService faceRecognitionAdaptorService = new FaceRecognitionAdaptorService();
        faceRecognitionAdaptorService.select(1).recognition(1001);
        faceRecognitionAdaptorService.select(2).recognition(1002);
    }
}


虽然说demo很简单,但是从代码的后期维护角度来说,我们可以得出以下两点经验:


  1. 使用了适配器模式其实有时候可以让两个独立的类各自发展,隔离他们之间的依赖,每当有类发生变化的时候只会影响到对应的类和适配器内部的代码,耦合程度可以大大降低。


  1. 而且在实际工作中,如果需要对系统的功能进行维护,可以通过采用适配器模式的方式来进行适配,从而减少对原先代码的侵入性。


代理模式的应用


什么是代理模式?


简单来讲就是在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。我们通过一个简单的例子来学习一下代理模式:


一个用户登录的接口代码如下所示:


public class UserService implements IUserService{
    @Override
    public void login() {
        System.out.println("UserService login...");
    }
}


可以结合代理模式,使用jdk代理的方式来进行接口的时长统计:


public class MetricsProxy {
    public Object createProxy(Object proxyObj){
        Class<?>[] interfaces = proxyObj.getClass().getInterfaces();
        DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(interfaces);
        return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(), interfaces, dynamicProxyHandler);
    }
    private class DynamicProxyHandler implements InvocationHandler {
        private Object proxiedObject;
        public DynamicProxyHandler(Object proxiedObject) {
            this.proxiedObject = proxiedObject;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            long begin = System.currentTimeMillis();
            Object result = method.invoke(proxiedObject, args);
            String apiName = proxiedObject.getClass().getName() + ":" + method.getName();
            long end = System.currentTimeMillis();
            System.out.println("接口耗时:"+(end - begin));
            return result;
        }
    }
    public static void main(String[] args) {
        MetricsProxy metricsProxy = new MetricsProxy();
        IUserService userService = (IUserService) metricsProxy.createProxy(new UserService());
        userService.login();
    }
}


除了上述的这种简单场景之外,实际上在我们工作中经常应用的rpc服务框架也有代理模式的影子。


例如说我们常用的dubbo框架,在进行远程化的服务调用过程中就是使用了代理模式的方式进行设计,使得用户端在调用接口的时候不需要去对底层的一些网络通信,数据编码做过多深入的了解。


为了更好地演示理解这个应用,下边我将通过一个实际案例来进行介绍:


首先是服务端代码:


public class RpcServer {
    public void export(Object service,int port){
        if(service==null || port<0 || port>65535){
            throw new RuntimeException("param is error");
        }
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            while (true){
                final Socket socket = serverSocket.accept();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
                            ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
                            String methodName = objectInputStream.readUTF();
                            Class<?>[] parameterTypes = (Class<?>[]) objectInputStream.readObject();
                            Object[] args = (Object[]) objectInputStream.readObject();
                            Method method = service.getClass().getMethod(methodName,parameterTypes);
                            Object result = method.invoke(service,args);
                            output.writeObject(result);
                        } catch (IOException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


客户端代码


public class RpcClient {
    public <T> T refer(final Class<T> interfaceClass, final String host, final int port) throws Exception {
        if(interfaceClass==null){
            throw new RuntimeException("interfaceClass is null");
        }else if (host==null){
            throw new RuntimeException("host is null");
        }else if (port<0 || port>65535){
            throw new RuntimeException("port is invalid ");
        }
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Socket socket = new Socket(host,port);
                OutputStream outputStream = socket.getOutputStream();
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
                objectOutputStream.writeUTF(method.getName());
                objectOutputStream.writeObject(method.getParameterTypes());
                objectOutputStream.writeObject(args);
                ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
                try {
                    Object result = input.readObject();
                    if (result instanceof Throwable) {
                        throw (Throwable) result;
                    }
                    return result;
                } finally {
                    input.close();
                }
            }
        });
    }
}


接着是一些测试使用的模拟服务,代码如下所示:


public interface IUserService {
    String test();
}
public class UserServiceImpl implements  IUserService {
    @Override
    public String test() {
        System.out.println("this is test");
        return "success";
    }
}


借助了使用代理模式设计的服务调用方和服务提供方,这里通过建立了两端的demo案例进行模拟:


首先是服务端代码:


public class ServerDemo {
    public static void main(String[] args) {
        RpcServer rpcServer = new RpcServer();
        IUserService userService = new UserServiceImpl();
        rpcServer.export(userService,9090);
    }
}


接着是客户端代码:


public class ClientDemo {
    public static void main(String[] args) throws Exception {
        RpcClient rpcClient = new RpcClient();
        IUserService iUserService = rpcClient.refer(IUserService.class,"localhost",9090);
        iUserService.test();
    }
}


本文总结


1.适配器模式是用来做适配,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。而且在对于系统维护的时候,适配器模式还可以作为一种用于补偿机制的设计模式来供开发者选用。


2.代理模式主要是在不改变原有类设计的基础上边通过引入相应的代理类来给原始类做扩展功能。常见的代理有划分为静态代理和动态代理两类。但是由于静态代理的可扩展性不好,因此实际工作中更多的场景会考虑使用动态代理的设计思路。比较常见的动态代理实现技术有cglib和jdk两类技术。然而使用JDK实现的动态代理不能完成继承式的动态代理,如果遇到这样的场景,可以使用cglib来实现继承式的动态代理。


3.适配器模式和代理模式两者都有点”包装(Wrapper)“数据的味道,其实这也是他们之间的一些共同性。如果要用他们的共性来划分,其实这两类设计模式可以统一称呼为结构型设计模式。


END

相关文章
|
3月前
|
设计模式 算法 开发者
探索编程语言中的设计模式:从理论到实践
设计模式,这一编程世界中的灯塔,为无数开发者照亮了复杂问题解决的道路。本文将深入探讨设计模式在编程实践中的运用,以代码示例揭示其背后的智慧。无论你是初学者还是资深开发者,都能在这里找到启发和共鸣。让我们一起领略设计模式的魅力,开启编程世界的新篇章!
|
3月前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践感悟####
本文作为一篇技术性文章,旨在深入探讨Python编程中设计模式的应用价值与实践心得。在快速迭代的软件开发领域,设计模式如同导航灯塔,指引开发者构建高效、可维护的软件架构。本文将通过具体案例,展现设计模式如何在实际项目中解决复杂问题,提升代码质量,并分享个人在实践过程中的体会与感悟。 ####
|
3月前
|
设计模式 监控 算法
Python编程中的设计模式应用与实践感悟###
在Python这片广阔的编程疆域中,设计模式如同导航的灯塔,指引着开发者穿越复杂性的迷雾,构建出既高效又易于维护的代码结构。本文基于个人实践经验,深入探讨了几种核心设计模式在Python项目中的应用策略与实现细节,旨在为读者揭示这些模式背后的思想如何转化为提升软件质量的实际力量。通过具体案例分析,展现了设计模式在解决实际问题中的独特魅力,鼓励开发者在日常编码中积极采纳并灵活运用这些宝贵的经验总结。 ###
|
4月前
|
设计模式 API 持续交付
深入理解微服务架构:设计模式与实践
【10月更文挑战第19天】介绍了微服务架构的核心概念、设计模式及最佳实践。文章详细探讨了微服务的独立性、轻量级通信和业务能力,并介绍了聚合器、链式和发布/订阅等设计模式。同时,文章还分享了实施微服务的最佳实践,如定义清晰的服务边界、使用API网关和服务发现机制,以及面临的挑战和职业心得。
|
4月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和复用性的关键技术之一。本文将通过探讨单例模式,一种最常用的设计模式,来揭示其在PHP中的应用及优势。单例模式确保一个类仅有一个实例,并提供一个全局访问点。通过实际案例,我们将展示如何在PHP项目中有效实现单例模式,以及如何利用这一模式优化资源配置和管理。无论是PHP初学者还是经验丰富的开发者,都能从本文中获得有价值的见解和技巧,进而提升自己的编程实践。
|
4月前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
【10月更文挑战第9天】 策略模式是一种行为设计模式,它允许在运行时选择算法的行为。在PHP开发中,通过使用策略模式,我们可以轻松切换算法或逻辑处理方式而无需修改现有代码结构。本文将深入探讨策略模式的定义、结构以及如何在PHP中实现该模式,并通过实际案例展示其应用价值和优势。
55 1
|
4月前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践###
【10月更文挑战第18天】 本文深入探讨了Python编程中设计模式的应用与实践,通过简洁明了的语言和生动的实例,揭示了设计模式在提升代码可维护性、可扩展性和重用性方面的关键作用。文章首先概述了设计模式的基本概念和重要性,随后详细解析了几种常用的设计模式,如单例模式、工厂模式、观察者模式等,在Python中的具体实现方式,并通过对比分析,展示了设计模式如何优化代码结构,增强系统的灵活性和健壮性。此外,文章还提供了实用的建议和最佳实践,帮助读者在实际项目中有效运用设计模式。 ###
41 0
|
4月前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
【10月更文挑战第12天】 在软件开发的世界中,设计模式是解决常见问题的最佳实践。它们不是具体的代码,而是一种编码和设计经验的总结。在PHP开发中,合理运用设计模式可以极大地提高代码的可维护性、扩展性和复用性。本文将深入探讨策略模式(Strategy Pattern)的原理、实现方式及其在PHP中的应用。通过具体示例,我们将展示如何利用策略模式来解耦算法与对象,从而让代码更加灵活和易于管理。
37 0
|
4月前
|
设计模式 存储 安全
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和重用性的关键技术之一。本文将深入探讨单例模式(Singleton Pattern)的原理、实现方式及其在PHP中的应用,同时通过实例展示如何在具体的项目场景中有效利用单例模式来管理和组织对象,确保全局唯一性的实现和最佳实践。
|
4月前
|
设计模式 存储 算法
PHP中的设计模式:策略模式的深入解析与实践
【10月更文挑战第9天】 在PHP开发领域,设计模式是提升代码可维护性、扩展性和重用性的关键技术之一。本文聚焦于策略模式这一行为型设计模式,通过理论阐述与实例分析,揭示其在PHP应用程序中优化算法切换和业务逻辑解耦方面的强大效用。不同于常规摘要,本文不直接概述研究方法或结果,而是基于实际开发场景,探讨策略模式的应用价值和实现方式,旨在为PHP开发者提供一种高效应对复杂业务需求变化和技术债务累积问题的策略思维。