工厂模式和策略模式
一、工厂模式
1.1简单工厂模式实现计算器
一般实现的计算器需要在客户端进行逻辑判断,在添加新的功能的时候需要修改很多的代码,而用简单工厂模式可以将逻辑判断的代码放在后台,而且在添加新的功能的时候也很容易。在不用的应用中也能复用。
首先创建Operation抽象类,将公有的方法getResult()设置为抽象函数
public abstract class Operation {
private double numberA;
private double numberB;
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public abstract double getResult();
}
对于不同的操作,创建不同的操作类,继承抽象操作类,然后各自实现抽象方法。
class OperationAdd extends Operation {
@Override
public double getResult() {
return getNumberA() + getNumberB();
}
}
class OperationSub extends Operation {
@Override
public double getResult() {
return getNumberA() - getNumberB();
}
}
class OperationMul extends Operation {
@Override
public double getResult() {
return getNumberA() * getNumberB();
}
}
class OperationDiv extends Operation {
@Override
public double getResult() {
if(getNumberB()==0){
System.out.println("除数不能为0");
return 0;
}else{
return getNumberA() * getNumberB();
}
}
}
然后,创建工厂类,根据字符串参数,实例化不同的操作类
public class OperationFactory {
public static Operation createOperation(String oper){
Operation operation=null;
switch (oper){
case "+":
operation=new OperationAdd();
break;
case "-":
operation=new OperationSub();
break;
case "*":
operation=new OperationMul();
break;
case "/":
operation=new OperationDiv();
break;
}
return operation;
}
}
最后进行测试
在简单工厂模式中,添加新的操作
首先,创建新的操作类,
class OperationPower extends Operation{
@Override
public double getResult() {
return Math.pow(getNumberA(),getNumberB());
}
}
其次,在工厂类中添加switch条件
case "pow":
operation=new OperationPower();
这样就添加了新的功能,测试如下:
1.2工厂方法模式
虽然简单工厂模式已经很好的实现了抽象和封装,但是它违反了开闭原则,开闭原则要求面向拓展开放而面向修改封闭,而且对于简单工厂模式,客户端只能通过传参数的方式控制类型,这样对于拥有用户界面的程序很有用,但是对于没有用户界面的程序,其他程序本身无法直接生成不同的操作符,这样就需要工厂方法模式。
Operation类保持不变
创建IFactory接口,然后对每个类型的操作符创建不同的接口,实现IFactory接口
public interface IFactory {
Operation createOperation();
}
class AddFactory implements IFactory{
@Override
public Operation createOperation() {
return new OperationAdd();
}
}
class SubFactory implements IFactory{
@Override
public Operation createOperation() {
return new OperationSub();
}
}
class MulFactory implements IFactory{
@Override
public Operation createOperation() {
return new OperationMul();
}
}
class DivFactory implements IFactory{
@Override
public Operation createOperation() {
return new OperationDiv();
}
}
这样在添加新的功能的时候,在后台只需要添加一个operation类和一个factory类,不需要进行修改,只需要修改前端调用的代码,符合开闭原则。
1.3抽象工厂模式
抽象工厂模式是用于创建一系列相关的对象的抽象接口,当工厂方法模式的对象为多个的时候,就要使用抽象工厂模式
用抽象工厂模式实现可移植的数据库访问。假设一个程序可能链接access数据库和sql server数据库,利用抽象工厂模式可以使数据库在改变是代码的修改最少。
假设数据库里面有一个用户User和产品Product表,首先创建者两个类
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Product {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
}
然后创建操作者两个类的接口
public interface IUser {
void insert(User user);
User getUser(int id);
}
public interface IProduct {
void insert(Product product);
Product getProduct(int id);
}
根据不同的数据库实现接口
对于User
public class SqlserverUser implements IUser{
@Override
public void insert(User user) {
System.out.println("Sqlserver 插入User表");
}
@Override
public User getUser(int id) {
System.out.println("Sqlserver 查找User表");
return null;
}
}
public class AccessUser implements IUser {
@Override
public void insert(User user) {
System.out.println("Access 插入User表");
}
@Override
public User getUser(int id) {
System.out.println("Access 查找User表");
return null;
}
}
对于product
public class SqlserverProduct implements IProduct {
@Override
public void insert(Product product) {
System.out.println("Sqlserver 插入Product表");
}
@Override
public Product getProduct(int id) {
System.out.println("Sqlserver 查找Product表");
return null;
}
}
public class AccessProduct implements IProduct {
@Override
public void insert(Product product) {
System.out.println("Access 插入Product表");
}
@Override
public Product getProduct(int id) {
System.out.println("Access 查找Product表");
return null;
}
}
创建抽象工厂接口
public interface IFactory {
IUser CreateUser();
IProduct CreateProduct();
}
创建sqlserverFactory
public class SqlaerverFactory implements IFactory {
@Override
public IUser CreateUser() {
return new SqlserverUser();
}
@Override
public IProduct CreateProduct() {
return new SqlserverProduct();
}
}
创建AccessFactory
public class AccessFactory implements IFactory {
@Override
public IUser CreateUser() {
return new AccessUser();
}
@Override
public IProduct CreateProduct() {
return new AccessProduct();
}
}
然后进行测试
public class AbstractFacTest {
public static void main(String[] args) {
User user=new User();
Product product=new Product();
//对于sql server数据库
IFactory database=new SqlaerverFactory();
//对于Access数据库
//IFactory database=new AccessFactory();
IUser iUser=database.CreateUser();
iUser.insert(user);
iUser.getUser(1);
IProduct iProduct=database.CreateProduct();
iProduct.insert(product);
iProduct.getProduct(1);
}
}
只需更改一句就能移植到其他数据库。
运行结果为:
当修改后
二、策略模式
商场经常会有不同的活动,加钱也会发生变化,如打八折和满300减80现在为商城设计一个软件,输入商品价格,根据不同的优惠返回最后要付的值,这种使用一系列不同算法的软件可以用策略模式进行设计。
先定义所有算法的公告接口CashSuper
public interface CashSuper {
double acceptCashh(double money);
}
然后创建封装的具体的算法类
class CashNormal implements CashSuper{
@Override
public double acceptCashh(double money) {
return money;
}
}
class CashRebate implements CashSuper{
private double moneyRebate=1.0;
public CashRebate(double moneyRebate){
this.moneyRebate=moneyRebate;
}
@Override
public double acceptCashh(double money) {
return money*moneyRebate;
}
}
class CashReturn implements CashSuper{
private double moneyCondition=1.0;
private double moneyReturn=1.0;
public CashReturn(double moneyCondition,double moneyReturn){
this.moneyCondition=moneyCondition;
this.moneyReturn=moneyReturn;
}
@Override
public double acceptCashh(double money) {
double result=money;
if(money>=moneyCondition){
result= money-Math.floor(money/moneyCondition)*moneyReturn;
}
return result;
}
}
创建一个Context完成对strategy的引用
public class CashContext {
private CashSuper cs;
public CashContext(String choose){
switch (choose){
case "无优惠":
cs=new CashNormal();
break;
case "打八折":
cs=new CashRebate(0.8);
break;
case "满300减80":
cs=new CashReturn(300,80);
}
}
public double getResult(double money){
return cs.acceptCashh(money);
}
}
在创建CashContext的时候使用了简单工厂模式,这样在test程序使用的时候,Test程序只用知道Context而不需要知道strategy类,降低了耦合
public class StrategyTest {
public static void main(String[] args){
Scanner in=new Scanner(System.in);
System.out.println("计算类别");
System.out.println("无优惠");
System.out.println("打八折");
System.out.println("满300减80");
System.out.println("请输入金额");
double money=Double.parseDouble(in.nextLine());
System.out.println("请输入选择计算类别:");
String choose=in.nextLine();
CashContext cashContext=new CashContext(choose);
System.out.printf("结果为%f",cashContext.getResult(money));
}
}
运算结果为: