“ 现实生活中,我们进经常会遇到满减活动或者打折活动,同一个促销活动可能后不同的策略,比如满30减5,满200打8折......用程序来实现的话,可以使用工厂设计模式+策略设计模式”
01
—
工厂设计模式
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,
并且是通过使用一个共同的接口来指向新创建的对象。
您需要一辆汽车,可以直接从工厂里面提货,
而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现
优点:
1、一个调用者想创建一个对象,只要知道其名称就可以了。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,
使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,
同时也增加了系统具体类的依赖。这并不是什么好事。
02
—
策略设计模式
一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
优点:
1、算法可以自由切换。
2、避免使用多重条件判断。
3、扩展性良好。
缺点:
1、策略类会增多。
2、所有策略类都需要对外暴露。
使用场景:
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,
那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2、一个系统需要动态地在几种算法中选择一种。
3、如果一个对象有很多的行为,如果不用恰当的模式,
这些行为就只好使用多重的条件选择语句来实现。
注意事项:如果一个系统的策略多于四个,
就需要考虑使用混合模式,解决策略类膨胀的问题
03
—
实战
//活动策略接口
interface ActivityStrategy{
//获取折扣后的金额方法
BigDecimal getDiscount(BigDecimal amount);
//根据类型获取具体活动策略对象
//根据它来去掉多重if-else,当然引入枚举后,该方法可以去掉
String getType();
}
//满30减5活动策略--具体实现类
class Full30Minus5ActivityStrategy implements ActivityStrategy{
@Override
public BigDecimal getDiscount(BigDecimal amount) {
return amount.subtract(BigDecimal.valueOf(5d)).setScale(2);
}
@Override
public String getType() {
return Full30Minus5ActivityStrategy.class.getName();
}
}
//满200打8折活动策略--具体实现类
class Full200Discount8ActivityStrategy implements ActivityStrategy{
@Override
public BigDecimal getDiscount(BigDecimal amount) {
return amount.multiply(BigDecimal.valueOf(0.8d)).setScale(2);
}
@Override
public String getType() {
return Full200Discount8ActivityStrategy.class.getName();
}
}
/**
* 活动策略工厂
*/
class ActivityStrategyFactory {
//静态内部类
public static class Holder {
public static ActivityStrategyFactory instance = new ActivityStrategyFactory();
}
//提供公有方法对外进行访问
public static ActivityStrategyFactory getInstance() {
return Holder.instance;
}
//私有构造函数,提供单例工厂
private ActivityStrategyFactory() {
}
//根据类型,通过反射获取具体活动策略对象
public ActivityStrategy getActivityStrategy(String type) {
try{
Objects.requireNonNull(type);//非空判断
return (ActivityStrategy) Class.forName(type).newInstance();
}catch(ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
04
—
枚举类
enum ActivityEnum{
FULL30_MINUS5(Full30Minus5ActivityStrategy.class.getName(),"满30元减5")
,FULL200_DISCOUNT8(Full200Discount8ActivityStrategy.class.getName(),"满200元,8折优惠")
,UNKNOW_ACTIVITY("未知活动策略","未知活动策略");
private String value;
private String description;
ActivityEnum(String value,String description){
this.value=value;
this.description=description;
}
public String getValue() {
return value;
}
public String getDescription() {
return description;
}
}
05
—
测试
public class ActivityStrategyTest{
public static void main(String[] args) {
//输入金额201.5
BigDecimal beforeDiscount=BigDecimal.valueOf(201.5);
ActivityEnum activityEnum;
if(beforeDiscount.doubleValue()>200){
activityEnum=ActivityEnum.FULL200_DISCOUNT8;
}else if(beforeDiscount.doubleValue()>30){
activityEnum=ActivityEnum.FULL30_MINUS5;
}else {
activityEnum=ActivityEnum.UNKNOW_ACTIVITY;
}
System.out.printf("该金额对应的策略是:%s%n",activityEnum.getDescription());
//具体业务,不用改动,变化的是参数,当有新的活动策略要添加时,只需要改动枚举参数即可
ActivityStrategy strategy = ActivityStrategyFactory.getInstance().getActivityStrategy(activityEnum.getValue());
BigDecimal afterDiscount = strategy.getDiscount(beforeDiscount);
System.out.println(afterDiscount);
}
}
写在最后
总结:本片使用枚举+工厂模式+策略模式去掉多重if...else,对于设计模式本小编也在不断研究中,虽然看起来很简单,但想要"悟"懂,也绝非易事,正所谓大道至简,设计模式也是我们程序设计中的基石,常言道:有道无术,其术可求也,有术无道,止于术!神即道,道即规律,道法自然.当然,此道非彼道,俗语云:"道可道,非常道".
往期精彩文章
关于BufferReader装饰设计模式的思考
Java设计模式之《观察者模式》及应用场景
从【Spring 源码的角度】读懂Java 23种设计模式之:动态代理设计模式
一文读懂Java 23种设计模式之:单例设计模式
如果喜欢,欢迎点赞分享给你身边需要的人!