java通过设计模式简化代码(SPI机制)

java通过设计模式简化代码(SPI机制)

设计模式原则(本次使用到的)

面向接口编程

模板方法

简单工厂模式

javaSPI机制

前闭后开原则

业务背景

现在有普通片,儿童片,新片,这几种类型的影片,用户可以选择需要租赁的天数和个数,然后程序自动结算出价格

传统开发模式
 switch (movieType) {
     case 'COMMON': 
         // 计算价格方法
     	 break;
     case 'CHILDREN':
         // 计算价格方法
     	 break;
     case 'NEW':
         // 计算价格方法
     	 break;
	 default :
         throw new Exception("无法获取影片类型");
 }

思考问题:通过传统的方式写,有哪些优缺点

优点:

代码逻辑简单,一眼能看懂

缺点:

维护困难:如果需求变更,需要添加一个影片类型,那需要对之前的代码进行修改,有修改,就有bug的风险

改进之后的模式

定义一个接口,以后所有的影片类型都实现这个接口,去完成自己独特的价格计算

package com.entity;

public class Movie {

    /**
     * 影片名称
     */
    private String movieName;

    /**
     * 影片价格
     */
    private Double moviePrice;

    /**
     * 影片库存
     */
    private Integer movieInventory;

    /**
     * 影片类型;1:普通篇;2:儿童片;3:新片
     */
    private Integer movieType;

    /**
     * 租的天数
     */
    private Double leaseDay;

    /**
     * 租几部
     * @return
     */
    private Integer leaseNumber;

    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    public Double getMoviePrice() {
        return moviePrice;
    }

    public void setMoviePrice(Double moviePrice) {
        this.moviePrice = moviePrice;
    }

    public Integer getMovieInventory() {
        return movieInventory;
    }

    public void setMovieInventory(Integer movieInventory) {
        this.movieInventory = movieInventory;
    }

    public Integer getMovieType() {
        return movieType;
    }

    public void setMovieType(Integer movieType) {
        this.movieType = movieType;
    }

    public Double getLeaseDay() {
        return leaseDay;
    }

    public void setLeaseDay(Double leaseDay) {
        this.leaseDay = leaseDay;
    }

    public Integer getLeaseNumber() {
        return leaseNumber;
    }

    public void setLeaseNumber(Integer leaseNumber) {
        this.leaseNumber = leaseNumber;
    }

    @Override
    public String toString() {
        return "Movie{" +
                "movieName='" + movieName + '\'' +
                ", moviePrice=" + moviePrice +
                ", movieInventory=" + movieInventory +
                ", movieType=" + movieType +
                ", leaseDay=" + leaseDay +
                ", leaseNumber=" + leaseNumber +
                '}';
    }
}

package com.movie;

import com.entity.Movie;

/**
 * 影片的计算价格接口
 */
public interface IMovePrice {

    /**
     * 计算价格
     * @param movie 影片对象
     * @return
     */
    double calculatePriceByMovie(Movie movie);

}
package com.movie;

import com.entity.Movie;

public class ChildrenMoviePrice implements IMovePrice {
    @Override
    public double calculatePriceByMovie(Movie movie) {
        double value = movie.getLeaseDay() * 4 + movie.getLeaseNumber() * 2.5;
        System.out.println("租了儿童片:" + movie.getLeaseDay() + "天,租了" + movie.getLeaseNumber() + "部,价格为:" + value);
        return value;
    }
}
package com.movie;

import com.entity.Movie;

public class CommonMoviePrice implements IMovePrice {

    @Override
    public double calculatePriceByMovie(Movie movie) {
        double value = movie.getLeaseDay() * 2 + movie.getLeaseNumber() * 1.5;
        System.out.println("租了普通片:" + movie.getLeaseDay() + "天,租了" + movie.getLeaseNumber() + "部,价格为:" + value);
        return value;
    }
}
package com.movie;

import com.entity.Movie;

public class NewMoviePrice implements IMovePrice {

    @Override
    public double calculatePriceByMovie(Movie movie) {
        double value = movie.getLeaseDay() * 3 + movie.getLeaseNumber() * 4.5;
        System.out.println("租了新片:" + movie.getLeaseDay() + "天,租了" + movie.getLeaseNumber() + "部,价格为:" + value);
        return value;
    }
}

我们加入了三种影片类型,分别实现接口IMovePrice,去完成各自影片类型的价格计算

package com.movie;

import com.entity.Movie;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

public class MoviePriceFactory {

    private IMovePrice movePrice;

    private static Map<String,String> propertiesMap = new HashMap<>();
	
    // 是不是很熟悉,springioc也是通过set方式注入的
    public void setMovePrice(IMovePrice movePrice) {
        this.movePrice = movePrice;
    }

    public MoviePriceFactory() {}


    public MoviePriceFactory(IMovePrice movePrice) {
        this.movePrice = movePrice;
    }
	
    // 调用方法,计算价格
    public double getMoviePrice (Movie movie) {
        return movePrice.calculatePriceByMovie(movie);
    }

    // 读取movieprice.properties文件内容,得到Map<String,String> 
    // key : 影片类型的Key;value:对应的接口实现类
    public static Map<String,String> getPropertiesMap () throws IOException {
        if (propertiesMap != null && propertiesMap.size() > 0) {
            return propertiesMap;
        }
        Properties properties = new Properties();
        properties.load(MoviePriceFactory.class.getClassLoader().getResourceAsStream("movieprice.properties"));

        Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Object, Object> next = iterator.next();
            propertiesMap.put(next.getKey().toString(), next.getValue().toString());
        }
        return propertiesMap;
    }
	
    // 通过影片类型得到对应的接口对象
    public static IMovePrice getIMovePriceMethod (String movieType) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        String implName = getPropertiesMap().get(movieType);
        Class c = Class.forName(implName);
        IMovePrice movePrice = (IMovePrice)c.newInstance();

        return movePrice;
    }
}

在这里,加入了movieprice.properties,维护影片类型key和对象实现的关系,后期如果有新的影片类型,我只需要实现IMovePrice接口,编写对应的计算逻辑,然后在movieprice.properties中加入对应关系即可,不需要再修改其他代码,我们做的都是扩展!!!

COMMONMOVIEPRICE=com.movie.CommonMoviePrice
CHILDRENMOVIEPRICE=com.movie.ChildrenMoviePrice
NEWMOVIEPRICE=com.movie.NewMoviePrice
package com.movie;

import com.entity.Movie;

import java.io.IOException;

public class TestJava {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
        Movie movie = new Movie();
        movie.setLeaseDay(2d);
        movie.setLeaseNumber(2);
		
        // 将获取对应的影片对象交给用户,是不是很熟悉,看到了springioc控制反转的影子
        MoviePriceFactory moviePriceFactory = new MoviePriceFactory(MoviePriceFactory.getIMovePriceMethod("CHILDRENMOVIEPRICE"));
        System.out.println(moviePriceFactory.getMoviePrice(movie));
    }
}

传统的模式中,我们是程序通过一些判断完成逻辑,而改进之后,我们把决定权交给了调用者(用户)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值