简单工厂模式与策略模式

工厂模式

工厂模式属于创建型模式,这个模式中不会暴露给你具体的创建过程,只会返给你
抽象的对相,就跟你去饭馆吃饭点了一个红烧鱼一样,你不需要知道这个红烧鱼是怎么做的,你要做的是吃就行。工厂模式侧重的是对象的创建;

实现规则很简单,首先有一个公共的抽象类或者接口,不同的行为分别继承自这个接口或者这个抽象类,具体定义一个工厂类,根据不同的特征来生产你想要的类。

比如说实现最简单的计算器功能:

  • 抽象类
public interface Operation {

    int operat(int num1, int num2);

}
  • 加法类
public class AddOperation implements Operation{


    @Override
    public int operat(int num1, int num2) {
        return num1 + num2;
    }

}
  • 减法类
public class SubtractionOperation implements Operation{

    @Override
    public int operat(int num1, int num2) {
        return num1 - num2;
    }

}
  • 工厂类
public class FactoryUtils {

    public static Operation createOperation(String op) {
        Operation operation = null;
        switch (op) {
        case "+":
            operation = new AddOperation(); 
            break;
        case "-":
            operation = new SubtractionOperation(); 
            break;
        default:
            break;
        }

        return operation;
    }
}
  • main方法
public class FactoryMain {

    public static void main(String[] args) {
        int num1 = 100;
        int num2 = 200;
        //加法
        Operation op = FactoryUtils.createOperation("+");
        int result = op.operat(num1, num2);
        System.out.println(result);
        //减法
        op = FactoryUtils.createOperation("-");
        result = op.operat(num1, num2);
        System.out.println(result);

    }
}

策略模式

策略模式是定义了一系列的算法,把这些算法封装起来,使他们之间可以相互替换,这些算法独立于他的客户端并且可以相互变化,其实就是客户不用不用关心他们是怎么实现的,只需要给我一个结果即可。
这里需要注意的是 策略模式注重的是行为算法,而工厂模式注重的是对象的创建
其实这两个是可以联合使用的。

策略模式的实现需要三个角色:

  • 抽象策略(strategy):定义一个抽象类或者接口,并给出具体策略的接口。
  • 具体策略:抽象策略的实现类,具体实现了相关的算法和行为。
  • 环境类:持有一个策略的引用。
    举个列子,还是比如上面的计算器:

  • 抽象策略

public interface Strategy {

    int operate(int num1, int num2);
}
  • 具体策略
package com.zyd.strategy.model;

public class AddStrategy implements Strategy{

    @Override
    public int operate(int num1, int num2) {
        return num1 + num2;

    }


}
package com.zyd.strategy.model;

public class SubtractionStrategy implements Strategy{

    @Override
    public int operate(int num1, int num2) {
        return num1 - num2;

    }


}
  • 环境类
package com.zyd.strategy.model;

public class Context {

    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }


    public void executeOperate(int num1, int num2) {
        System.out.println(strategy.operate(num1, num2));
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public Strategy getStrategy() {
        return strategy;
    }
}
  • 具体调用
package com.zyd;

import com.zyd.strategy.model.AddStrategy;
import com.zyd.strategy.model.Context;
import com.zyd.strategy.model.SubtractionStrategy;

public class StrategyMain {
    public static void main(String[] args) {
        Context context = new Context(new AddStrategy());
        context.executeOperate(10, 100);

        Context context1 = new Context(new SubtractionStrategy());
        context1.executeOperate(10, 100);
    }
}

策略模式到此就实现完了,其实很简单。
前面我们也提到了工厂模式,实际上在通常的做法中,这两种是可以结合起来的,利用工厂模式来创建对象:

package com.zyd.strategy.model;

public class FactoryUtil {

    public static Strategy createStragegy(String op) {
        Strategy Strategy = null;
        switch (op) {
        case "+":
            Strategy = new AddStrategy(); 
            break;
        case "-":
            Strategy = new SubtractionStrategy(); 
            break;
        default:
            break;
        }

        return Strategy;
    }
}

而实际调用的代码就变成了这样:

package com.zyd;

import com.zyd.strategy.model.Context;
import com.zyd.strategy.model.FactoryUtil;

public class StrategyMain {
    public static void main(String[] args) {
        Context context = new Context(FactoryUtil.createStragegy("+"));
        context.executeOperate(10, 100);

        Context context1 = new Context(FactoryUtil.createStragegy("-"));
        context1.executeOperate(10, 100);
    }
}

策略模式和工厂模式到这就基本结束了,是不是很简单?
其实还可以更进阶一点,如果我们在增加一个乘法或者除法的,那我们就必须去修工厂类,再加一个case才行,这个是简单工厂模式的缺点,有什么办法来解决这个事情么? 肯定有的,那就是注解。

那么首先 我们定义一个元注解:

package com.zyd.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationOperation {

    String operate() default "+";
}

ElementType.TYPE表示只作用于类
@Retention(RetentionPolicy.RUNTIME) 运行是注解
真正关键是实现简单工厂类:

package com.zyd.strategy.model;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.GenericArrayType;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import com.zyd.annotation.AnnotationOperation;

public class FactoryUtil {

    private String packageName = this.getClass().getPackage().getName();
    private  ClassLoader loader = this.getClass().getClassLoader();

    //获取包名下的所有类的名字
    private List getPackageNames(String pkgName){

        List list = new ArrayList<>();
        try {
            File file = new File(loader.getResource(pkgName.replace(".", "/")).toURI());
            String[] names = file.list();
            for (String str : names) {
                if(str.endsWith(".class")) {
                    list.add(str);
                }
            }
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return list;
    }
    //根据包名,加载出所有的类
    private  List getClasses(List names){
        List list = new ArrayList<>();
        for (String name : names) {
            try {
                Class clazz = loader.loadClass(packageName + "." + name.replace(".class", ""));

                list.add(clazz);
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return list;
    }

    public  Strategy createStragegy(String op) {
        try {
            List list = getClasses(getPackageNames(packageName));
            for (Class class1 : list) {
                if(FactoryUtil.class.equals(class1) 
                        || Strategy.class.equals(class1)
                        || Context.class.equals(class1)) {
                    continue;
                }
                Annotation[] ans = class1.getAnnotations();
                AnnotationOperation ope = null;
                for(Annotation an : ans) {
                    if(an instanceof AnnotationOperation) {
                        ope = (AnnotationOperation) an;
                        break;
                    }
                }

                if(ope != null) {
                    if(ope.operate().equals(op)) {
                        return (Strategy) class1.newInstance();
                    }
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
        return null;
    }
}

那么main方法就要改成这样了:

package com.zyd;

import com.zyd.strategy.model.Context;
import com.zyd.strategy.model.FactoryUtil;

public class StrategyMain {
    public static void main(String[] args) {
        FactoryUtil util = new FactoryUtil();
        Context context = new Context(util.createStragegy("+"));
        context.executeOperate(10, 100);

        Context context1 = new Context(util.createStragegy("-"));
        context1.executeOperate(10, 100);
    }
}

上面的注解很简单,稍微有点注解基础应该就能看懂

这样话如果你要是添加一个乘法类的话,只需要实现策略类,并且添加注解就OK了。
欢迎关注我的公众号: manong_xiaodong
简单工厂模式与策略模式_第1张图片

你可能感兴趣的:(设计模式)