现在的生活中在线支付给我们的生活带来了极大的方便,出门可以不用带钱,只要带上手机出门就可以消费了。而支付方式也是多种多样的,可以选择支付宝,微信,银行卡等多种支付方式。张三所在公司最近就需要根据用户选择的支付方式,去调用不同的支付接口对账户进行扣款,下面是他写的代码:
1.直接就是消费者类:
// 消费者类
public class Consumer {
// 设置默认支付方式
private String payType = "AliPay";
public void pay(int money) {
if ("AliPay".equals(payType)) {
System.out.println("使用支付宝支付~~");
// 调用支付宝支付接口。。。
System.out.println("扣款成功,消费:" + money + "元");
} else if ("WeChatPay".equals(payType)) {
System.out.println("使用微信支付~~");
// 调用微信支付接口。。。
System.out.println("扣款成功,消费:" + money + "元");
} else if ("BankCardPay".equals(payType)) {
System.out.println("使用银行卡支付~~");
// 调用银行卡支付接口。。。
System.out.println("扣款成功,消费:" + money + "元");
}
}
public void setPayType(String payType) {
this.payType = payType;
}
}
2.客户端使用:
public class Main {
public static void main(String[] args) {
Consumer consumer = new Consumer();
int money = 100;
consumer.pay(money);
consumer.setPayType("WeChatPay");
consumer.pay(money);
consumer.setPayType("BankCardPay");
consumer.pay(money);
}
}
3.使用结果:
使用支付宝支付~~
扣款成功,消费:100元
使用微信支付~~
扣款成功,消费:100元
使用银行卡支付~~
扣款成功,消费:100元
张三通过在pay()
方法中判断用户选择的支付方式分别调用不用的支付接口,最终完成的任务。但是代码中一个很明显的缺点就是pay()
方法非常庞大,它包含了支付接口的实现代码,使得方法会很长。同时方法中的if...else...
语句如果在扩展其他支付方式时会有更多的判断。还有就是方法中的调用接口代码不能给其他需要调用支付接口的方法进行复用。基于此张三很快想到了可以使用策略模式来对代码进行改进。
策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。
在策略模式中,我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里,每一个封装算法的类我们都可以称之为一种策略(Strategy),为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类。
角色构成
UML类图
下面张三就通过策略模式对代码进行改造:
1.首先定义出抽象的策略接口:
// 抽象策略接口,抽象策略类角色
public interface Pay {
void deduction(int money);
}
2.三个具体的策略类:
支付宝:
// 支付宝支付,具体策略类角色
public class AliPay implements Pay {
@Override
public void deduction(int money) {
System.out.println("使用支付宝支付~~");
// 调用支付宝支付接口。。。
System.out.println("扣款成功,消费:" + money + "元");
}
}
微信支付
// 微信支付,具体策略类角色
public class WeChatPay implements Pay {
@Override
public void deduction(int money) {
System.out.println("使用微信支付~~");
// 调用微信支付接口。。。
System.out.println("扣款成功,消费:" + money + "元");
}
}
银行卡支付
// 银行卡支付,具体策略类角色
public class BankCardPay implements Pay {
@Override
public void deduction(int money) {
System.out.println("使用银行卡支付~~");
// 调用银行卡支付接口。。。
System.out.println("扣款成功,消费:" + money + "元");
}
}
3.消费者类充当环境类角色:
// 消费者类,环境类角色
public class Consumer {
// 设置默认支付方式
private Pay pay = new AliPay();
public void pay(int money) {
pay.deduction(money);
}
// 切换支付方式
public void setPay(Pay pay) {
this.pay = pay;
}
}
4.客户端使用:
public class Main {
public static void main(String[] args) {
Consumer consumer = new Consumer();
int money = 100;
consumer.pay(money);
consumer.setPay(new WeChatPay());
consumer.pay(money);
consumer.setPay(new BankCardPay());
consumer.pay(money);
}
}
5.使用结果:
使用支付宝支付~~
扣款成功,消费:100元
使用微信支付~~
扣款成功,消费:100元
使用银行卡支付~~
扣款成功,消费:100元
经过改造后使用结果和上面的结果相同,但不同的是现在的支付方式可以很好的进行扩展了。只需要新建一个具体支付策略类实现支付接口,使用时选择新建的支付接口就可以了。
策略模式在开发中应用非常广泛,常见的就是比较器Comparator
接口和java.awt.Container
,下面简单分析一下在 java 容器布局中的应用。
1.首先是如下案列代码:
public class Main {
public static void main(String[] args) {
// 创建 JFrame 实例
JFrame jf = new JFrame("layout example");
// 设置宽高
jf.setSize(500, 400);
// 设置在窗口中间打开
jf.setLocationRelativeTo(null);
// 设置默认关闭操作
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 边界布局
// 默认为0,0;水平间距10,垂直间距5
JPanel borderLayoutPanel = new JPanel(new BorderLayout(10, 5));
TitledBorder titledBorder = new TitledBorder("BorderLayout");
borderLayoutPanel.setBorder(titledBorder);
JButton north = new JButton("东");
JButton south = new JButton("南");
JButton east = new JButton("西");
JButton west = new JButton("北");
JButton middle = new JButton("中");
borderLayoutPanel.add(north, BorderLayout.EAST);
borderLayoutPanel.add(south, BorderLayout.SOUTH);
borderLayoutPanel.add(east, BorderLayout.WEST);
borderLayoutPanel.add(west, BorderLayout.NORTH);
borderLayoutPanel.add(middle, BorderLayout.CENTER);
// 将面板添加到窗体中
jf.add(borderLayoutPanel, BorderLayout.WEST);
// 变换布局按钮
JButton changeToGridLayout = new JButton("changeToGridLayout");
// 设置监听器
changeToGridLayout.addActionListener(e -> {
// 将边界布局改变为网格布局
borderLayoutPanel.setLayout(new GridLayout(2, 3, 10, 5));
titledBorder.setTitle("GridLayout");
// 更新之后界面才会发生改变
borderLayoutPanel.updateUI();
});
// 将按钮添加进窗体中
jf.add(changeToGridLayout, BorderLayout.EAST);
// 设置界面可见
jf.setVisible(true);
}
}
2.演示动图
可以看到,我们通过修改borderLayoutPanel.setLayout(new GridLayout(2, 3, 10, 5))
方法可以动态的设置界面的布局方式,除了设置为边界布局和网格布局外,还可以设置为流式布局(FlowLayout)、盒子布局(BoxLaYout)和空布局(null)等。下面是他们之间的 UML 类图关系:
通过源码我们可以看到,setLayout(LayoutManager mgr)
方法不是JPanel
类中的方法,而是父类Container
中的方法,它扮演了环境类的角色,具体代码为:
public class Container extends Component {
// 抽象布局对象
LayoutManager layoutMgr;
// 通过 setLayout() 方法修改
public void setLayout(LayoutManager mgr) {
layoutMgr = mgr;
invalidateIfValid();
}
}
而这里的抽象策略者角色就由LayoutManager
接口扮演,而具体策略类有边界布局BorderLayout
、流式布局FlowLayout
、网格布局GridLayout
、盒子布局BoxLayout
等。在使用时设置不同的布局对象,就会呈现不同的展示效果。
主要优点
主要缺点
适用场景
本篇文章github代码地址:https://github.com/Phoegel/design-pattern/tree/main/strategy
转载请说明出处,本篇博客地址:https://www.cnblogs.com/phoegel/p/14248318.html
原文:https://www.cnblogs.com/phoegel/p/14248318.html