栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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;

    
    private Integer movieType;

    
    private Double leaseDay;

    
    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 {

    
    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 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 
    // key : 影片类型的Key;value:对应的接口实现类
    public static Map getPropertiesMap () throws IOException {
        if (propertiesMap != null && propertiesMap.size() > 0) {
            return propertiesMap;
        }
        Properties properties = new Properties();
        properties.load(MoviePriceFactory.class.getClassLoader().getResourceAsStream("movieprice.properties"));

        Iterator> iterator = properties.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry 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));
    }
}

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/284708.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号