【长沙研发中心】代码重构之设计模式

简介: 代码重构之设计模式

代码重构之设计模式


1、什么是重构?


       重构大致可以理解为,在保持功能不变的前提下,利用设计思想、原则、模式、编程规范等理论来优化代码,修改设计上的不足,提高代码质量。


2、 为什么要重构?


首先随着项目的不断演进,代码在堆砌,不免会产生一些过时的、冗余代码等。就需要重新整理,重新设计,使代码恢复设计模式和设计原则的限制。当然这里对于设计而言,重构是避免过度设计的有效手段。同时对于个人而言,重构也很锻炼程序员的功底,这是对设计模式,设计原则的实际应用,能快速提升程序员的水平。


3、介绍本次讲解重构中用到的4种设计模式:


1 工厂方法


追 MM 少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是 MM 爱吃的东西,虽然口味有所不同,但不管你带 MM 去麦当劳或肯德基,只管向服务员说「来四个鸡翅」就行了。麦当劳和肯德基就是生产鸡翅的 Factory 工厂模式:客户类和工厂类分开。


消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。


2 策略模式


跟不同类型的 MM 约会,要用不同的策略,有的请电影比较好,有的则去吃小吃效果不错,有的去海边浪漫最合适,其实都是为了得到 MM 的芳心,追 MM 锦囊中有好多 Strategy 哦。策略模式:策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。


策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模把行为和环境分开。环境类负责维持和查询行为类,各种算法在具体的策略类中提供。由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。


3 模板方法模式


比如说追女孩子步骤分为巧遇、打破僵局、展开追求、约会等步骤 (Template method),但每个步骤针对不同的情况,都有不一样的做法,这就要看你随机应变啦 (具体实现);


模板方法模式:模板方法模式准备一个抽象类,将部分逻辑以具体方法以及具体构造子类的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。


4 责任链模式


晚上去上英语课,为了好开溜坐到了最后一排,哇,前面坐了好几个漂亮的 MM 哎,找张纸条,写上 “Hi, 可以做我的女朋友吗?如果不愿意请向前传”,纸条就一个接一个的传上去了,糟糕,传到第一排的 MM 把纸条传给老师了,听说是个老处女呀,快跑!


责任链模式:在责任链模式中,很多对象由每一个对象对其下家的引用而接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。


在我们的项目中if ... else往往是用的最多的,而且到处都能看到大量的if ... else。那么if ... else 如果太多就会存在以下缺点:


a、代码逻辑复杂,维护性差,极容易引发 bug。


b、 耦合性强,不利于拓展。


c、容易引起误解和理解困难。


d、业务复杂还会导致代码臃肿。


4、常用的场景案例讲解:

public interface PayService {
    void toPay(String code);
}
@Service
public class AliPay implements IPay {
    @Override
    public void pay() {
        // 处理支付宝支付逻辑
        System.out.println("===支付宝支付===");
    }
}
@Service
public class UnionPay implements IPay {
    @Override
    public void pay() {
        // 银联支付逻辑
        System.out.println("===银联支付===");
    }
}
@Service
public class WechatPay implements IPay {
    @Override
    public void pay() {
        // 微信支付逻辑
        System.out.println("===微信支付===");
    }
}
@Service
public class PayServiceImpl implements PayService {
    @Autowired
    private AliPay aliPay;
    @Autowired
    private UnionPay unionPay;
    @Autowired
    private WechatPay wechatPay;
    @Override
    public void toPay(String code) {
        // 支付宝支付
        if (PayCodeEnum.ALI_PAY.getCode().equals(code)) {
            aliPay.pay();
            // 银联支付
        } else if (PayCodeEnum.UNION_PAY.getCode().equals(code)) {
            unionPay.pay();
            // 微信支付
        } else if (PayCodeEnum.WECHAT_PAY.getCode().equals(code)) {
            wechatPay.pay();
        } else {
            System.out.println("找不到支付方式");
        }
    }
}


思考下,这段代码应该如何去优化??? 这段代码存在哪些问题???


存在问题:


试想一下,如果支付方式越来越多,比如:后续项目需要增加京东支付、百度支付、美团支付等等,就需要修改toPay方法的代码,增加更多的else...if判断,业务越来越多,判断多了就会导致逻辑越来越多。


同时也违反了设计模式六大原则的:“开闭原则” 和“单一职责原则”


开闭原则:对扩展开放,对修改关闭。就是说增加新功能要尽量少改动已有代码。


单一职责原则:逻辑尽量单一,不要太复杂,便于复用 。


有哪些优化方案????


5、优化方案:


优化方案一:注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PayCode {
    String value();
    String name();
}
@PayCode(value = "ALI_PAY",name = "支付宝支付")
@Service
public class AliPay implements IPay {
    @Override
    public void pay() {
        // 处理支付宝支付逻辑
        System.out.println("===支付宝支付===");
    }
}
@PayCode(value = "UNION_PAY", name = "银联支付")
@Service
public class UnionPay implements IPay {
    @Override
    public void pay() {
        // 银联支付逻辑
        System.out.println("===银联支付===");
    }
}
@PayCode(value = "WECHAT_PAY", name = "微信支付")
@Service
public class WechatPay implements IPay {
    @Override
    public void pay() {
        // 微信支付逻辑
        System.out.println("===微信支付===");
    }
}
@Service
public class PayServiceAnnotationImpl implements PayService, ApplicationListener<ContextRefreshedEvent> {
    private static Map<String, IPay> payMap = null;
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(PayCode.class);
        if (null != beansWithAnnotation) {
            payMap = new HashMap<>();
            beansWithAnnotation.forEach((key, value) -> {
                String bizType = value.getClass().getAnnotation(PayCode.class).value();
                payMap.put(bizType, (IPay) value);
            });
        }
    }
    @Override
    public void toPay(String code) {
        payMap.get(code).pay();
    }
}


优化方案二:模板方法
public interface IPay {
    void pay();
    Boolean support(String code);
}
@Service
public class AliPay implements IPay {
    @Override
    public void pay() {
        // 处理支付宝支付逻辑
        System.out.println("===支付宝支付===");
    }
    @Override
    public Boolean support(String code) {
        return PayCodeEnum.ALI_PAY.getCode().equals(code);
    }
}
@Service
public class UnionPay implements IPay {
    @Override
    public void pay() {
        // 银联支付逻辑
        System.out.println("===银联支付===");
    }
    @Override
    public Boolean support(String code) {
        return PayCodeEnum.UNION_PAY.getCode().equals(code);
    }
}
@Service
public class WechatPay implements IPay {
    @Override
    public void pay() {
        // 微信支付逻辑
        System.out.println("===微信支付===");
    }
    @Override
    public Boolean support(String code) {
        return PayCodeEnum.WECHAT_PAY.getCode().equals(code);
    }
}
@Service
public class PayServiceTemplateMethodImpl implements PayService, ApplicationContextAware, InitializingBean {
    private ApplicationContext applicationContext;
    private List payList = null;
    @Override
    public void afterPropertiesSet() throws Exception {
        if (null != payList) {
            payList = new ArrayList<>();
            Map beansOfType = applicationContext.getBeansOfType(IPay.class);
            beansOfType.forEach((key, value) -> payList.add(value));
        }
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
    }
    @Override
    public void toPay(String code) {
        for (IPay iPay : payList) {
            if (iPay.support(code)) {
                iPay.pay();
            }
        }
    }
}


优化方案三:工厂+策略模式


最优方案

/**
* 支付策略工厂类
*/
public class PayStrategyFactory {
    private static Map payMap = new HashMap<>();
    public static void register(String code, IPay iPay) {
        if (StringUtils.isNotEmpty(code)) {
            payMap.put(code, iPay);
        }
    }
    public static IPay get(String code) {
        return payMap.get(code);
    }
}
@Service
public class AliPay implements IPay {
    @PostConstruct
    public void init(){
        PayStrategyFactory.register(PayCodeEnum.ALI_PAY.getCode(),this);
    }
    @Override
    public void pay() {
        // 处理支付宝支付逻辑
        System.out.println("===支付宝支付===");
    }
}
@Service
public class UnionPay implements IPay {
    @PostConstruct
    public void init(){
        PayStrategyFactory.register(PayCodeEnum.UNION_PAY.getCode(),this);
    }
    @Override
    public void pay() {
        // 银联支付逻辑
        System.out.println("===银联支付===");
    }
}
@Service
public class WechatPay implements IPay {
    @PostConstruct
    public void init(){
        PayStrategyFactory.register(PayCodeEnum.WECHAT_PAY.getCode(),this);
    }
    @Override
    public void pay() {
        // 微信支付逻辑
        System.out.println("===微信支付===");
    }
}
@Service
public class PayServiceStrategyFactoryImpl implements PayService {
    @Override
    public void toPay(String code) {
        PayStrategyFactory.get(code).pay();
    }
}


优化方案四:责任链模式  (只为解释该设计模式使用)
@Data
public abstract class PayHandler {
    private PayHandler nextPayHandler;
    public abstract void pay(String code);
}
@Service
public class AliPayHandler extends PayHandler {
    @Override
    public void pay(String code) {
        if (PayCodeEnum.ALI_PAY.getCode().equals(code)) {
            System.out.println("===支付宝支付===");
        } else {
            getNextPayHandler().pay(code);
        }
    }
}
@Service
public class UnionPayHandler extends PayHandler {
    @Override
    public void pay(String code) {
        if (PayCodeEnum.UNION_PAY.getCode().equals(code)) {
            System.out.println("===银联支付===");
        } else {
            getNextPayHandler().pay(code);
        }
    }
}
@Service
public class WechatPayHandler extends PayHandler {
    @Override
    public void pay(String code) {
        if (PayCodeEnum.WECHAT_PAY.getCode().equals(code)) {
            System.out.println("===微信支付===");
        } else {
            getNextPayHandler().pay(code);
        }
    }
}
@Service
public class PayHandlerChainServiceImpl implements PayService, ApplicationContextAware, InitializingBean {
    private ApplicationContext applicationContext;
    private PayHandler payHandler;
    @Override
    public void afterPropertiesSet() throws Exception {
        Map beansOfType = applicationContext.getBeansOfType(PayHandler.class);
        if (beansOfType.isEmpty()) {
            return;
        }
        List handlers = beansOfType.values().stream().collect(Collectors.toList());
        for(int i = 0 ; i < handlers.size(); i++ ) {
            PayHandler handler = handlers.get(i);
            if (i != handlers.size() - 1) {
                handler.setNextPayHandler(handlers.get(i + 1));
            }
        }
        payHandler = handlers.get(0);
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
    }
    @Override
    public void toPay(String code) {
        payHandler.pay(code);
    }
}


6、思考:如何利用设计模式优化


if ("文本".equals(type)) {
            // do something
        } else if ("图片".equals(type)) {
            // do something
        } else if ("视频".equals(type)) {
            // do something
        } else {
            // do something
        }


answer:

@Data
public class MessageInfo {
    private Integer type;
    private String content;
}
public interface MessageService {
   void handleMessage(MessageInfo messageInfo);
}
@MessageHandlerAnnotation(value = MsgTypeEnum.TEXT)
@Service
public class TextMessageService implements MessageService{
    @Override
    public void handleMessage(MessageInfo messageInfo) {
        System.out.println("===文本消息===" + messageInfo.getContent());
    }
}
@MessageHandlerAnnotation(value = MsgTypeEnum.IMAGE)
@Service
public class ImageMessageService implements MessageService{
    @Override
    public void handleMessage(MessageInfo messageInfo) {
        System.out.println("===图片消息===" + messageInfo.getContent());
    }
}
@MessageHandlerAnnotation(value = MsgTypeEnum.VIDEO)
@Service
public class VideoMessageService implements MessageService{
    @Override
    public void handleMessage(MessageInfo messageInfo) {
        System.out.println("===视频消息===" + messageInfo.getContent());
    }
}
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.TYPE)
public @interface MessageHandlerAnnotation {
    MsgTypeEnum value();
}
public enum MsgTypeEnum {
    TEXT(1, "文本"),
    IMAGE(2, "图片"),
    VIDEO(3, "视频");
    public final int code;
    public final String name;
    MsgTypeEnum(int code, String name){
        this.code = code;
        this.name = name;
    }
}
@Component
public class MessageServiceContext {
    private final Map handlerMap = new HashMap<>();
    public MessageService getMessageService(Integer code) {
       return handlerMap.get(code);
    }
    public void putMessageService(Integer code, MessageService messageService) {
        handlerMap.put(code, messageService);
    }
}
@Component
public class MessageServiceListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        Map beansWithAnnotation = contextRefreshedEvent.getApplicationContext().getBeansWithAnnotation(MessageHandlerAnnotation.class);
        MessageServiceContext messageServiceContext = contextRefreshedEvent.getApplicationContext().getBean(MessageServiceContext.class);
        beansWithAnnotation.forEach((key, value) -> {
            MessageHandlerAnnotation messageHandler = value.getClass().getAnnotation(MessageHandlerAnnotation.class);
            messageServiceContext.putMessageService(messageHandler.value().code, (MessageService) value);
        });
    }
}
@SpringBootTest
class DesignModeApplicationTests {
    @Autowired
    private MessageServiceContext messageServiceContext;
    @Test
    void contextLoads() {
        MessageInfo messageInfo = new MessageInfo();
        messageInfo.setType(1);
        messageInfo.setContent("文本文本");
        MessageService messageService = messageServiceContext.getMessageService(messageInfo.getType());
        messageService.handleMessage(messageInfo);
    }
}


目录
打赏
0
0
1
0
1
分享
相关文章
MVC革命:如何用一个设计模式重塑你的应用架构,让代码重构变得戏剧性地简单!
【8月更文挑战第22天】自定义MVC(Model-View-Controller)设计模式将应用分为模型、视图和控制器三个核心组件,实现关注点分离,提升代码可维护性和扩展性。模型管理数据和业务逻辑,视图负责数据显示与用户交互,控制器处理用户输入并协调模型与视图。通过示例代码展示了基本的MVC框架实现,可根据需求扩展定制。MVC模式灵活性强,支持单元测试与多人协作,但需注意避免控制器过度复杂化。
72 1
【Java设计模式 规范与重构】 六 代码重构小结
【Java设计模式 规范与重构】 六 代码重构小结
254 0
好教程推荐系列:《代码重构和设计模式》《重学Java设计模式》,C++11实现全套设计模式
好教程推荐系列:《代码重构和设计模式》《重学Java设计模式》,C++11实现全套设计模式
188 0
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
206 11
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
设计模式:工厂方法模式(Factory Method)
工厂方法模式是一种创建型设计模式,通过将对象的创建延迟到子类实现解耦。其核心是抽象工厂声明工厂方法返回抽象产品,具体工厂重写该方法返回具体产品实例。适用于动态扩展产品类型、复杂创建逻辑和框架设计等场景,如日志记录器、数据库连接池等。优点包括符合开闭原则、解耦客户端与具体产品;缺点是可能增加类数量和复杂度。典型应用如Java集合框架、Spring BeanFactory等。
|
2月前
|
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
96 40
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
「全网最细 + 实战源码案例」设计模式——简单工厂模式
简单工厂模式是一种创建型设计模式,通过工厂类根据传入参数创建不同类型的对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。适用于对象种类较少且调用者无需关心创建细节的场景。
76 19
「全网最细 + 实战源码案例」设计模式——生成器模式
生成器模式(Builder Pattern)是一种创建型设计模式,用于分步骤构建复杂对象。它允许用户通过控制对象构造的过程,定制对象的组成部分,而无需直接实例化细节。该模式特别适合构建具有多种配置的复杂对象。其结构包括抽象建造者、具体建造者、指挥者和产品角色。适用于需要创建复杂对象且对象由多个部分组成、构造过程需对外隐藏或分离表示与构造的场景。优点在于更好的控制、代码复用和解耦性;缺点是增加复杂性和不适合简单对象。实现时需定义建造者接口、具体建造者类、指挥者类及产品类。链式调用是常见应用方式之一。
67 12
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等