为什么要在代码中使用设计模式,因为代码最重要的是要让别人看懂。在一些优秀的开源项目中,大量的使用了设计模式,代码的可读性非常高。在实际的项目开发中,针对一些特定的场景使用设计模式,能让代码可读性更高,扩展性更强。
1 策略模式
策略,Strategy。在解决一个问题的时候,可能会有很多种解法,每种解法对应一个算法,针对不同的场景随意切换,提高代码的灵活性。优势在于在需要修改时,只需要针对某个策略修改,不需要动整体框架。
例如北京公交车,10km以内1元钱,超过10km之外的,没超出5km就会多加1元钱;北京地铁,6km内3元,6-12km(含)内4元,12-22km(含)内5元,22-32km(含)内6元。
两种策略:公交和地铁出行,根据里程数,计算出对应的价格。
1.1 基础策略模式
public class PriceCalculator {
public enum TYPE{
BUS,SUBWAY
}
public static void main(String[] args){
PriceCalculator priceCalculator = new PriceCalculator();
int busPrice = priceCalculator.calculatePrice(20,TYPE.BUS);
int subwayPrice = priceCalculator.calculatePrice(10,TYPE.SUBWAY);
System.out.println("20km公交车的价格:"+busPrice+",20km地铁的价格:"+subwayPrice);
}
/**
* 策略1 乘坐公交车
* @param km
* @return
*/
public int busPrice(int km){
//基础价格10元,10km以内
int basePrice = 1;
//超出的公里数
int offsetDistance = km - 10;
//没有超出10km
if(offsetDistance < 0){
return basePrice;
}
//计算超出5km的
int radio = offsetDistance / 5;
return basePrice + radio * 1;
}
/**
* 策略2 乘坐地铁
* @param km
* @return
*/
public int subwayPrice(int km){
if(km <= 6){
return 3;
}else if(km > 6 && km <= 12){
return 4;
}else if(km > 12 && km <= 22){
return 5;
}else if(km > 22 && km <= 32){
return 6;
}
return 7;
}
/**
* 针对不同的策略,计算相应的价格
* @param km
* @param type
* @return
*/
public int calculatePrice(int km,TYPE type){
if(type == TYPE.BUS){
return busPrice(km);
}else if(type == TYPE.SUBWAY){
return subwayPrice(km);
}
return -1;
}
}
这种框架存在的问题包括:
(1)PriceCalculator 违背了单一职责原则,不仅计算了公交的价格,还计算了地铁的价格;
(2)calculatePrice方法,使用了if-else来判断使用哪个策略,违背了开闭原则,如果有1000种方式,那么需要写1000个if-else。
所以,策略模式,就是用来代替if-else,可动态地选择对应的策略。
1.2 动态策略模式
第一步:新建一个接口,其中设置各个策略类计算价格的方法。
public interface IPriceStrategy {
//计算价格
int price(int km);
}
第二步:不同策略实现类实现该接口
public class BusPriceStrategy implements IPriceStrategy{
@Override
public int price(int km) {
//基础价格1元,10km以内
int basePrice = 1;
//超出的公里数
int offsetDistance = km - 10;
//没有超出10km
if(offsetDistance < 0){
return basePrice;
}
//计算超出5km的
int radio = offsetDistance / 5;
return basePrice + radio * 1;
}
}
public class SubwayStrategy implements IPriceStrategy{
@Override
public int price(int km) {
if(km <= 6){
return 3;
}else if(km > 6 && km <= 12){
return 4;
}else if(km > 12 && km <= 22){
return 5;
}else if(km > 22 && km <= 32){
return 6;
}
return 7;
}
}
每个策略实现类的价格算法,都是之前PriceCalculator 类中拷贝过来的。
第三步:策略上下文,统一调度策略算法。
public class PriceStrategy {
private IPriceStrategy mStrategy;
public PriceStrategy(){}
/**
* 动态调度算法
* @param strategy
*/
public void setStrategy(IPriceStrategy strategy){
this.mStrategy = strategy;
}
/**
* 根据具体实现类,调用价格计算的方法
* @param km
* @return
*/
public int calculatePrice(int km){
return mStrategy.price(km);
}
}
通过setStrategy方法来切换对应的策略,避免使用if-else是的代码变得臃肿,难以维护。如果价格的计算方式改变,只需要改变BusPriceStrategy或者SubwayStrategy两个类的计算算法,整体调用的框架,在这里是不需要修改的,具备扩展性。
PriceStrategy priceStrategy = new PriceStrategy();
priceStrategy.setStrategy(new BusPriceStrategy());
int busPrice = priceStrategy.calculatePrice(20);
priceStrategy.setStrategy(new SubwayStrategy());
int subwayPrice = priceStrategy.calculatePrice(20);
System.out.println("20km公交车的价格:"+busPrice+",20km地铁的价格:"+subwayPrice);
2 工厂模式
工厂模式可用户构建复杂的对象,如果通过new就能创建的对象没有必要使用工厂模式。
例如,A工厂生产A类产品,B工厂生产B类产品…
2.1 简单工厂模式
public interface IProduct {
//产品
void create();
}
A产品
public class AProduct implements IProduct{
@Override
public void create() {
System.out.println("我是A类工厂的A产品");
}
}
B产品
public class BProduct implements IProduct {
@Override
public void create() {
System.out.println("我是B类工厂的B产品");
}
}
简单工厂方法,通过if-else判断产品类型来生成对应的产品,缺点在策略模式中讲过,在此不过多赘述。
public class ProductFactory {
enum Product{
A,B
}
private IProduct mProduct;
//根据Product类型判断
public void createProduct(Product product){
if(product == Product.A){
mProduct= new AProduct ();
}else if(product == Product.B){
mProduct= new BProduct ();
}
}
public void create(){
mProduct.create();
}
}
简单工厂模式,仅适用于产品固定的场景(这种场景基本很少出现),否则将会违背开闭原则。每增加一个产品,需要添加一次if-else。
@Test
public void test(){
ProductFactory factory = new ProductFactory();
factory.createProduct(ProductFactory.Product.A);
factory.create();
// AFactory
}
2.2 工厂方法模式
工厂方法模式解决了简单工厂模式的弊端,每个产品对应一个工厂。
/**
* 工厂方法模式
*/
public interface IFactoryBuild {
//创建工厂的方法
IProduct build();
}
A工厂
public class AFactory implements IFactoryBuild {
@Override
public IProduct build() {
//生成A产品
return new AProduct();
}
}
B工厂
public class BFactory implements IFactoryBuild {
@Override
public IProduct build() {
return new BProduct();
}
}
根据需求,如果需要生产A产品,就创建A类工厂,生产B产品就创建B类工厂。
AFactory aFactory = new AFactory();
IProduct product = aFactory.build();
product.create();
弊端在于,如果存在很多工厂,那么需要创建很多工厂。
public class ProductFactory {
public IFactoryBuild createFactory(Class<? extends IFactoryBuild> mFactory){
try {
return mFactory.newInstance();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
}
2.3 抽象工厂设计模式
抽象工厂设计模式与工厂方法一致,只不过抽象工厂模式适用于大规模批量生产的场景。
例如不同的手机,性能配置都不同。小米手机配置的是高通CPU,8核,红米手机配置的是联发科CPU,4核,那么使用抽象工厂设计模式,设计对应的手机。
产品:CPU、核心数、小米手机、红米手机
public interface CPU {
void run();
class GaotongCpu implements CPU{
@Override
public void run() {
System.out.println("高通CPU");
}
}
class lianfakeCpu implements CPU{
@Override
public void run() {
System.out.println("联发科CPU");
}
}
}
public interface Core {
void run();
class core8 implements Core{
@Override
public void run() {
System.out.println("8核");
}
}
class core4 implements Core{
@Override
public void run() {
System.out.println("4核");
}
}
}
工厂:小米工厂、红米工厂
public interface IMobileFactory {
CPU getCpu();
Core getCore();
}
public class XiaoMiFactory implements IMobileFactory {
@Override
public CPU getCpu() {
//高通的CPU
return new CPU.GaotongCpu();
}
@Override
public Core getCore() {
//8核
return new Core.core8();
}
}
public class RedMiFactory implements IMobileFactory{
@Override
public CPU getCpu() {
return new CPU.lianfakeCpu();
}
@Override
public Core getCore() {
return new Core.core4();
}
}
XiaoMiFactory factory = new XiaoMiFactory();
factory.getCpu().run();
factory.getCore().run();
输出结果:
高通CPU
8核