工厂模式属于创建型模式,这个模式中不会暴露给你具体的创建过程,只会返给你
抽象的对相,就跟你去饭馆吃饭点了一个红烧鱼一样,你不需要知道这个红烧鱼是怎么做的,你要做的是吃就行。工厂模式侧重的是对象的创建;
实现规则很简单,首先有一个公共的抽象类或者接口,不同的行为分别继承自这个接口或者这个抽象类,具体定义一个工厂类,根据不同的特征来生产你想要的类。
比如说实现最简单的计算器功能:
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;
}
}
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);
}
}
策略模式是定义了一系列的算法,把这些算法封装起来,使他们之间可以相互替换,这些算法独立于他的客户端并且可以相互变化,其实就是客户不用不用关心他们是怎么实现的,只需要给我一个结果即可。
这里需要注意的是 策略模式注重的是行为算法,而工厂模式注重的是对象的创建
其实这两个是可以联合使用的。
策略模式的实现需要三个角色:
环境类:持有一个策略的引用。
举个列子,还是比如上面的计算器:
抽象策略
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