【设计模式——学习笔记】23种设计模式——策略模式Strategy(原理讲解+应用场景介绍+案例介绍+Java代码实现)

简介: 【设计模式——学习笔记】23种设计模式——策略模式Strategy(原理讲解+应用场景介绍+案例介绍+Java代码实现)

案例引入

  • 有各种鸭子,比如野鸭、北京鸭、水鸭等。 鸭子有各种行为,比如走路、叫、飞行等。不同鸭子的行为可能略有不同。要求显示鸭子的信息

传统方案实现

不同的鸭子继承一个父类Duck,如果是相同的行为就继承,不同行为就重写方法

实现

【鸭子抽象类】

package com.atguigu.strategy;
public abstract class Duck {
   public Duck() {
   }
   /**
    * 显示鸭子信息
    */
   public abstract void display();
   /**
    * 叫法
    */
   public void quack() {
      System.out.println("鸭子嘎嘎叫~~");
   }
   /**
    * 游泳方法
    */
   public void swim() {
      System.out.println("鸭子会游泳~~");
   }
   /**
    * 飞翔方法
    */
   public void fly() {
      System.out.println("鸭子会飞翔~~~");
   }
}

【野鸭】

package com.atguigu.strategy;
public class WildDuck extends Duck {
   @Override
   public void display() {
      System.out.println(" 这是野鸭 ");
   }
}

【北京鸭】

package com.atguigu.strategy;
public class PekingDuck extends Duck {
   @Override
   public void display() {
      System.out.println("~~北京鸭~~~");
   }
   /**
    * 因为北京鸭不能飞翔,因此需要重写fly
    */
   @Override
   public void fly() {
      System.out.println("北京鸭不能飞翔");
   }
}

【玩具鸭】

package com.atguigu.strategy;
public class ToyDuck extends Duck {
    @Override
    public void display() {
        System.out.println("玩具鸭");
    }
    //-------需要重写父类的所有方法---------
    public void quack() {
        System.out.println("玩具鸭不能叫~~");
    }
    public void swim() {
        System.out.println("玩具鸭不会游泳~~");
    }
    public void fly() {
        System.out.println("玩具鸭不会飞翔~~~");
    }
}

分析

  • 缺点:因为继承了Duck,所有鸭子都有了会飞的方法,虽然可以通过覆盖fly方法来解决,但是,如果子类很多方法都不需要呢,如果每个都要去覆盖一下就很麻烦了
  • 改进:使用策略模式

介绍

基本介绍

  • 策略模式中,定义算法族,分别封装到不同的类中,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。使用策略模式可以整体地替换算法的实现部分,让我们可以轻松地以不同的算法去解决同一个问题
  • 该模式体现了几个设计原则:把变化的代码从不变的代码中分离出来;针对接口编程而不是具体类(定义了策略接口);多用组合/聚合,少用继承(客户通过组合方式使用策略)

登场角色

Context聚合了策略接口,后面需要使用到哪个具体策略的方法,就传入该具体策略的实例作为参数即可

  • Strategy(策略):Strategy角色负责定义实现策略所必需的接口(API)
  • ConcreteStrategy(具体的策略):ConcreteStrategy角色负责实现Strategy角色的接口(API),即负责实现具体的策略(战略、方向、方法和算法)
  • Context(上下文):负责使用Strategy角色。Context角色保存了ConcreteStrategy角色的实例,并使用ConcreteStrategy角色(即调用Strategy角色的接口)去实现需求

案例实现

案例一

类图

实现

【飞翔策略 FlyBehavior】

package com.atguigu.strategy.improve;
public interface FlyBehavior {
   /**
    * 让子类具体实现
    */
   void fly();
}

【叫策略 QuackBehavior】

package com.atguigu.strategy.improve;
public interface QuackBehavior {
   void quack();
}

【飞翔技术高超:GoodFlyBehavior】

package com.atguigu.strategy.improve;
public class GoodFlyBehavior implements FlyBehavior {
   @Override
   public void fly() {
      System.out.println(" 飞翔技术高超 ~~~");
   }
}

【飞翔技术一般:BadFlyBehavior 】

package com.atguigu.strategy.improve;
public class BadFlyBehavior implements FlyBehavior {
   @Override
   public void fly() {
      System.out.println(" 飞翔技术一般 ");
   }
}

【不会飞翔】

package com.atguigu.strategy.improve;
public class NoFlyBehavior implements FlyBehavior{
   @Override
   public void fly() {
      System.out.println(" 不会飞翔  ");
   }
}

【鸭子抽象类】

package com.atguigu.strategy.improve;
public abstract class Duck {
   /**
    * 策略接口 飞翔
    */
   FlyBehavior flyBehavior;
   /**
    * 策略接口 叫
    */
   QuackBehavior quackBehavior;
   public Duck() {
   }
   /**
    * 显示鸭子信息
    */
   public abstract void display();
   public void quack() {
      System.out.println("鸭子嘎嘎叫~~");
   }
   public void swim() {
      System.out.println("鸭子会游泳~~");
   }
   public void fly() {
      //改进
      if(flyBehavior != null) {
         flyBehavior.fly();
      }
   }
   public void setFlyBehavior(FlyBehavior flyBehavior) {
      this.flyBehavior = flyBehavior;
   }
   public void setQuackBehavior(QuackBehavior quackBehavior) {
      this.quackBehavior = quackBehavior;
   }
}

【野鸭】

package com.atguigu.strategy.improve;
public class WildDuck extends Duck {
   /**
    * 构造器,传入FlyBehavor 的对象
    */
   public  WildDuck() {
      // 野鸭飞翔技术较强
      flyBehavior = new GoodFlyBehavior();
   }
   @Override
   public void display() {
      System.out.println(" 这是野鸭 ");
   }
}

【北京鸭】

package com.atguigu.strategy.improve;
public class PekingDuck extends Duck {
    /**
     * 假如北京鸭可以飞翔,但是飞翔技术一般
     */
    public PekingDuck() {
        flyBehavior = new BadFlyBehavior();
    }
    @Override
    public void display() {
        System.out.println("~~北京鸭~~~");
    }
}

【玩具鸭】

package com.atguigu.strategy.improve;
public class ToyDuck extends Duck {
    public ToyDuck() {
        // 玩具鸭不会飞翔
        flyBehavior = new NoFlyBehavior();
    }
    @Override
    public void display() {
        System.out.println("玩具鸭");
    }
    /**
     * 需要重写父类的所有方法
     */
    public void quack() {
        System.out.println("玩具鸭不能叫~~");
    }
    public void swim() {
        System.out.println("玩具鸭不会游泳~~");
    }
}

【主类】

package com.atguigu.strategy.improve;
public class Client {
   public static void main(String[] args) {
      WildDuck wildDuck = new WildDuck();
      wildDuck.fly();
      ToyDuck toyDuck = new ToyDuck();
      toyDuck.fly();
      PekingDuck pekingDuck = new PekingDuck();
      pekingDuck.fly();
      //可以动态改变某个对象的行为, 将北京鸭改成不能飞
      pekingDuck.setFlyBehavior(new NoFlyBehavior());
      System.out.println("北京鸭的实际飞翔能力");
      pekingDuck.fly();
   }
}

【输出】

飞翔技术高超 ~~~
 不会飞翔  
 飞翔技术一般 
北京鸭的实际飞翔能力
 不会飞翔  
Process finished with exit code 0

尖叫策略和飞翔策略的实现方式一样,这里就不再实现了

案例二

类图

实现

【手势类:并不是策略模式的角色】

package com.atguigu.strategy.Sample;
/**
 * 手势
 */
public class Hand {
    /**
     * 表示石头的值
     */
    public static final int HANDVALUE_GUU = 0;
    /**
     * 表示剪刀的值
     */
    public static final int HANDVALUE_CHO = 1;
    /**
     * 表示布的值
     */
    public static final int HANDVALUE_PAA = 2;
    /**
     * 表示猜拳中3种手势的实例
     */
    public static final Hand[] hand = {
            new Hand(HANDVALUE_GUU),
            new Hand(HANDVALUE_CHO),
            new Hand(HANDVALUE_PAA),
    };
    /**
     * 表示猜拳中手势所对应的字符串
     */
    private static final String[] name = {
            "石头", "剪刀", "布",
    };
    /**
     * 表示猜拳中出的手势的值
     */
    private int handvalue;
    private Hand(int handvalue) {
        this.handvalue = handvalue;
    }
    /**
     * 根据手势的值获取其对应的实例,这是一种单例模式,每种手势只有一个实例
     *
     * @param handvalue
     * @return
     */
    public static Hand getHand(int handvalue) {
        return hand[handvalue];
    }
    /**
     * 如果this胜了h则返回true
     *
     * @param h
     * @return
     */
    public boolean isStrongerThan(Hand h) {
        return fight(h) == 1;
    }
    /**
     * 如果this输给了h则返回true
     *
     * @param h
     * @return
     */
    public boolean isWeakerThan(Hand h) {
        return fight(h) == -1;
    }
    /**
     * 计分:平0, 胜1, 负-1
     *
     * @param h
     * @return
     */
    private int fight(Hand h) {
        if (this == h) {
            return 0;
        } else if ((this.handvalue + 1) % 3 == h.handvalue) {
            // 当(this.handvalue + 1) % 3 == h.handvalue时,可能得手势组合如下
            // this是石头,h是剪刀
            // this是剪刀,h是布
            // this是布,h是石头
            return 1;
        } else {
            return -1;
        }
    }
    /**
     * 转换为手势值所对应的字符串
     *
     * @return
     */
    public String toString() {
        return name[handvalue];
    }
}

【策略接口】

package com.atguigu.strategy.Sample;
public interface Strategy {
    /**
     * 获取下一局要出的手势
     * @return
     */
    public abstract Hand nextHand();
    /**
     * 学习上一局的手势是否获胜了,获胜就传进来true,否则返回false
     * @param win
     */
    public abstract void study(boolean win);
}

【具体策略一】

package com.atguigu.strategy.Sample;
import java.util.Random;
/**
 * 该策略是:如果上一局赢了,这局的手势就和上一局的相同;如果上一局输了,就随机出
 */
public class WinningStrategy implements Strategy {
    private Random random;
    /**
     * 保存上一局是赢还是输了
     */
    private boolean won = false;
    /**
     * 保存上一局出的手势
     */
    private Hand prevHand;
    public WinningStrategy(int seed) {
        random = new Random(seed);
    }
    public Hand nextHand() {
        if (!won) {
            prevHand = Hand.getHand(random.nextInt(3));
        }
        return prevHand;
    }
    public void study(boolean win) {
        won = win;
    }
}

【具体策略二】

package com.atguigu.strategy.Sample;
import java.util.Random;
public class ProbStrategy implements Strategy {
    private Random random;
    private int prevHandValue = 0;
    private int currentHandValue = 0;
    /**
     * 过去的胜率:history[上一局出的手势][这一局所出的手势]
     * 假设上一局出的手势是石头:
     * history[0][0]:两局分别出了石头、石头的获胜次数
     * history[0][1]:两局分别出了石头、剪刀的获胜次数
     * history[0][2]:两局分别出了石头、布的获胜次数
     * 若history[0][0]=3;history[0][1]=5;history[0][2]=7
     * 下一把出什么?使用轮盘赌的方式,出石头的概率是3/15;出剪刀的概率是5/15;出布的概率是7/15
     */
    private int[][] history = {
        { 1, 1, 1, },
        { 1, 1, 1, },
        { 1, 1, 1, },
    };
    public ProbStrategy(int seed) {
        random = new Random(seed);
    }
    /**
     * 学习历史胜率,根据轮盘赌的方式来出下一个手势
     * @return
     */
    public Hand nextHand() {
        int bet = random.nextInt(getSum(currentHandValue));
        int handvalue = 0;
        if (bet < history[currentHandValue][0]) {
            handvalue = 0;
        } else if (bet < history[currentHandValue][0] + history[currentHandValue][1]) {
            handvalue = 1;
        } else {
            handvalue = 2;
        }
        prevHandValue = currentHandValue;
        currentHandValue = handvalue;
        return Hand.getHand(handvalue);
    }
    /**
     * 获取第一把出hv,第二把出1、2、3的总次数
     * @param hv
     * @return
     */
    private int getSum(int hv) {
        int sum = 0;
        for (int i = 0; i < 3; i++) {
            sum += history[hv][i];
        }
        return sum;
    }
    /**
     * 学习经验,更新 history 表格
     * @param win
     */
    public void study(boolean win) {
        if (win) {
            history[prevHandValue][currentHandValue]++;
        } else {
            history[prevHandValue][(currentHandValue + 1) % 3]++;
            history[prevHandValue][(currentHandValue + 2) % 3]++;
        }
    }
}

【游戏选手类】

package com.atguigu.strategy.Sample;
/**
 * 玩猜拳游戏的选手类
 */
public class Player {
    private String name;
    /**
     * 记录选手要选用的策略
     */
    private Strategy strategy;
    /**
     * 赢的局数
     */
    private int wincount;
    /**
     * 输的局数
     */
    private int losecount;
    /**
     * 总局数
     */
    private int gamecount;
    /**
     * 传入选手的姓名和策略
     *
     * @param name
     * @param strategy
     */
    public Player(String name, Strategy strategy) {
        this.name = name;
        this.strategy = strategy;
    }
    /**
     * 策略决定下一局要出的手势
     *
     * @return
     */
    public Hand nextHand() {
        return strategy.nextHand();
    }
    /**
     * 猜拳胜利
     */
    public void win() {                 
        strategy.study(true);
        wincount++;
        gamecount++;
    }
    /**
     * 猜拳失败
     */
    public void lose() {                
        strategy.study(false);
        losecount++;
        gamecount++;
    }
    /**
     * 猜拳平局
     */
    public void even() {                
        gamecount++;
    }
    public String toString() {
        return "[" + name + ":" + gamecount + " games, " + wincount + " win, " + losecount + " lose" + "]";
    }
}

【主类】

package com.atguigu.strategy.Sample;
public class Main {
    public static void main(String[] args) {
        // 让选手分别使用两种策略来比试
        Player player1 = new Player("Taro", new WinningStrategy(314));
        Player player2 = new Player("Hana", new ProbStrategy(12));
        for (int i = 0; i < 10000; i++) {
            Hand nextHand1 = player1.nextHand();
            Hand nextHand2 = player2.nextHand();
            if (nextHand1.isStrongerThan(nextHand2)) {
//                System.out.println("Winner:" + player1);
                player1.win();
                player2.lose();
            } else if (nextHand2.isStrongerThan(nextHand1)) {
//                System.out.println("Winner:" + player2);
                player1.lose();
                player2.win();
            } else {
//                System.out.println("Even...");
                player1.even();
                player2.even();
            }
        }
        System.out.println("Total result:");
        System.out.println(player1.toString());
        System.out.println(player2.toString());
    }
}

【运行】

Total result:
[Taro:10000 games, 3107 win, 3617 lose]
[Hana:10000 games, 3617 win, 3107 lose]
Process finished with exit code 0

问答

如果需要增加一个随机出手势的策略,需要怎么实现

答:在nextHand方法中使用随机数即可,因为全部都是随机的,不需要学习之前的经验,因此study方法可以是空方法

在示例程序中,Hand类的fight方法负责判断平局。在进行判断时,它使用的表达式不是this.handValue == h.value,而是this==h,请问为什么可以这样写?

答:因为使用了单例模式,只有三个手势实例,如果两个手势的handValue相同,说明两个实例就是同一个实例


编写Winningstrategy类时,won 字段的定义不是private boolean won = false; 而是写成了如下这样private boolean won;虽然写法不同,但是两者的运行结果一样,为什么?


答:因为全局变量如果没有被赋值就会被自动初始化:boolean类型默认是false;数值类型默认是0;引用类型默认是null。注意,局部变量不会被自动初始化

策略模式在JDK源码中的使用

简单来说,就是在排序的时候,可以指定不同的排序策略

package com.atguigu.jdk;
import java.util.Arrays;
import java.util.Comparator;
public class Strategy {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //数组
        Integer[] data = {9, 1, 2, 8, 4, 3};
        // 实现降序排序,返回-1放左边,1放右边,0保持不变
        // 说明
        // 1. 实现了 Comparator 接口(策略接口) , 匿名类对象:new Comparator<Integer>(){..}
        // 2. 对象 new Comparator<Integer>(){..} 就是实现了 策略接口 的对象
        // 3. public int compare(Integer o1, Integer o2){} 指定具体的处理策略
        Comparator<Integer> comparator = new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                if (o1 > o2) {
                    return -1;
                } else {
                    return 1;
                }
            }
        };
        // sort源码说明 传入数字和一个排序策略
      /*
       * public static <T> void sort(T[] a, Comparator<? super T> c) {
              if (c == null) {
                  sort(a); //默认方法
              } else {
                  if (LegacyMergeSort.userRequested)
                      legacyMergeSort(a, c); //使用策略对象c
                  else
                     // 使用策略对象c
                      TimSort.sort(a, 0, a.length, c, null, 0, 0);
              }
          }
       */
        // 方式1
        Arrays.sort(data, comparator);
      // 降序排序
        System.out.println(Arrays.toString(data));
        //方式2- 同时lambda 表达式实现 策略模式
        Integer[] data2 = {19, 11, 12, 18, 14, 13};
        // 换一个排序策略
        Arrays.sort(data2, (var1, var2) -> {
            if (var1.compareTo(var2) > 0) {
                return -1;
            } else {
                return 1;
            }
        });
        System.out.println("data2=" + Arrays.toString(data2));
    }
}

总结

【说明】

  • 策略模式的关键是分析项目中变化部分与不变部分

【优点】

  • 策略模式的核心思想是:多用组合/聚合,少用继承;用行为类来组合,而不是行为的继承
  • 体现了“对修改关闭,对扩展开放”原则,客户端增加行为不用修改原有代码,只要添加一种策略 (或者行为)即可,避免了使用多重判断语句 (if…else if…else)
  • 提供了可以替换继承关系的办法: 策略模式将算法封装在独立的Strategy类中使得你可以独立于其他Context改变它,使它易于切换、易于理解、易于扩展
  • 程序运行过程中也可以切换策略:如果使用Strategy模式,在程序运行中也可以切换ConcreteStrategy角色。如在内存较少的环境使用一种算法,内存较多的环境使用另外一种算法

【缺点】

  • 每添加一个策略就要增加一个类,当策略过多是会导致类数目庞大

【问答】

为什么需要特意编写Strategy角色

答:当我们想要通过改善算法来提高算法的处理速度时,如果使用了Strategy模式,就不必修改Strategy角色的接口(API)了,仅仅修改ConcreteStrategy角色即可。而且,使用委托这种弱关联关系可以很方便地整体替换算法,这样也更加方便算法的比较

文章说明

  • 本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。
  • 本人还同步阅读《图解设计模式》书籍(图解设计模式/(日)结城浩著;杨文轩译–北京:人民邮电出版社,2017.1),进而综合两者的内容,让知识点更加全面
目录
相关文章
|
6天前
|
传感器 监控 Java
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
26 5
|
8天前
|
开发框架 Java 开发工具
【Java全栈学习笔记-U1-day01】Java介绍
本笔记整理了Java学习的基础内容,涵盖程序理解、Java语言特性、JDK安装与配置、Java程序开发工具及编写步骤。重点介绍了Java程序的基本结构、编译和运行过程,以及输出语句的使用。通过实例演示了IDEA创建Java程序的方法,并强调了编码规范和注意事项。适合初学者复习和交流学习。 主要内容: 1. 理解程序:计算机组成、程序定义。 2. 简介:Java语言特点、技术平台、JDK作用。 3. 编写Java程序:编写、编译、运行步骤,基本结构。 4. 输出语句 5. DEA使用:新建工程、保存位置、文件介绍、新建类。 6. 扩展:注释、代码规范、大小写敏感、缩进等。
|
1月前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
179 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
2月前
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
418 11
|
2月前
|
JSON Java 数据挖掘
利用 Java 代码获取淘宝关键字 API 接口
在数字化商业时代,精准把握市场动态与消费者需求是企业成功的关键。淘宝作为中国最大的电商平台之一,其海量数据中蕴含丰富的商业洞察。本文介绍如何通过Java代码高效、合规地获取淘宝关键字API接口数据,帮助商家优化产品布局、制定营销策略。主要内容包括: 1. **淘宝关键字API的价值**:洞察用户需求、优化产品标题与详情、制定营销策略。 2. **获取API接口的步骤**:注册账号、申请权限、搭建Java开发环境、编写调用代码、解析响应数据。 3. **注意事项**:遵守法律法规与平台规则,处理API调用限制。 通过这些步骤,商家可以在激烈的市场竞争中脱颖而出。
|
3月前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
90 3
|
5天前
|
设计模式 Java 关系型数据库
设计模式:工厂方法模式(Factory Method)
工厂方法模式是一种创建型设计模式,通过将对象的创建延迟到子类实现解耦。其核心是抽象工厂声明工厂方法返回抽象产品,具体工厂重写该方法返回具体产品实例。适用于动态扩展产品类型、复杂创建逻辑和框架设计等场景,如日志记录器、数据库连接池等。优点包括符合开闭原则、解耦客户端与具体产品;缺点是可能增加类数量和复杂度。典型应用如Java集合框架、Spring BeanFactory等。
|
2月前
|
设计模式 Java
「全网最细 + 实战源码案例」设计模式——生成器模式
生成器模式(Builder Pattern)是一种创建型设计模式,用于分步骤构建复杂对象。它允许用户通过控制对象构造的过程,定制对象的组成部分,而无需直接实例化细节。该模式特别适合构建具有多种配置的复杂对象。其结构包括抽象建造者、具体建造者、指挥者和产品角色。适用于需要创建复杂对象且对象由多个部分组成、构造过程需对外隐藏或分离表示与构造的场景。优点在于更好的控制、代码复用和解耦性;缺点是增加复杂性和不适合简单对象。实现时需定义建造者接口、具体建造者类、指挥者类及产品类。链式调用是常见应用方式之一。
63 12
|
2月前
|
设计模式
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
92 40
|
2月前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——工厂方法模式
简单工厂模式是一种创建型设计模式,通过一个工厂类根据传入参数创建不同类型的产品对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。适用于创建对象种类较少且调用者无需关心创建细节的场景。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。
56 15

热门文章

最新文章