文章目录
1.“组件协作”模式
“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合。 典型模式:
Strategy
Template Method
Observer/Event
2.策略模式动机(Motivation)
在运行时根据需要透明地更改对象的算法,将算法与对象本身解耦
3.问题引入
商场收银软件
输入单价和数量
算出每种商品的小计
记录商品的清单
记录总计
4.商场收银系统1.0
import java.util.Scanner;
public class Cash{
public String list=" ";
public Double totalPrice=0.00; //声明一个double变量totalPrice来计算总计
public void buttonOK(){
Scanner scan=new Scanner(System.in);
System.out.println("输入单价:");
String price=scan.nextLine();
scan=new Scanner(System.in);
System.out.println("输入数量:");
String num=scan.nextLine();
Double xiaoji=Double.parseDouble(price)*Integer.parseInt(num);
//声明一个xiaoji来计算每个商品的单价*数量后的合计
list+="单价:"+price+",数量:"+num+",小计:"+xiaoji+"\n";
//清单
totalPrice+=xiaoji;
//每个商品计入小计
}
public static void main(String[] args){
Cash cash=new Cash();
boolean flag=true;
while(flag){ //循环终止条件可改
cash.buttonOK();
if(cash.totalPrice>10){
flag=false;
}
}
System.out.println("=============");
System.out.println("清单:\n"+cash.list);
System.out.println("总价:"+cash.totalPrice);
//如果商场商品打折
//加下拉选择框或输入折扣可以解决
//即在buttonOK类中输入数量的下面加上
scan =new scanner(Systen.in);
System.out.println("输入折扣:");
String zhekou=scan.nextLine();
//并且小计的计算中需要改变如下:
Double xiaoji=Double.parseDouble(price)*Integer.parseInt(num)*Double.parseDouble(zhekou)/10;
//如果增加满减促销活动或则折扣种类过多将会难以实现
5. 使用简单工厂模式
用简单工厂模式:
现金收费抽象类CashSuper,里有收取现金的方法acceptCash()
有三种方案:正常收费,打折收费,满减收费
工厂类,封装现金收费类
import java.util.Scanner;
//现金收取父类
abstract class CashSuper{
public abstract double acceptCash(double money);
}
//正常收费类
class CashNormal extends CashSuper{
@Override
public double acceptCash(double money){
return money;
}
}
//打折收费类,继承CashSuper
class CashRebate extends CashSuper{
private double discount=0.00;
//初始化时,必须输入折扣率,如八折就是0.8
public CashRebate(double discount){
this.discount=discount/10;
}
@override
public double acceptCash(double money){
return this.discount*monwy;
//返利收费,继承CashSuper
class CashReturn extends CashSuper{
private double baseCash;//基础金额
private double returnCash;//返现金额
//初始化时必须要输入返利条件和返回值,比如满300反100,则baseCash为300,returnCash为100
public CashReturn(double baseCash,double reurnCash){
this.baseCash=baseCash;
this.returnCash=returnCash;
}
@overrride
public double acceptCash(double money){
double result=money;
if(money>=baseCash)//若大于返利条件,则需要减去返利值
result=money-Math.floor(money/baseCash)*returnCash;
//函数Math.floor(x)返回小于x的最大整数值
return result;
}
public double getBaseCash(){ return baseCash; }
public void setBaseCash(double baseCash) { this.baseCash=baseCash; }
public double getReturnCash() { return returnCash; }
public void setReturnCash(double returnCash) { this.returnCash=returnCash; }
}
//现金收取工厂
class CashAcceptFactory{
//根据条件生成相应的对象
//静态方法特点可以使用类名调用
public static CashSuper createCashAccept(String type,double discount,double basePrice,double returnPrice){
CashSuper cs=null;
if("1".equals(type)) cs=new CashNormal();
else
if("2".equals(type)) cs=new CashRebate(discount);
else
if("3".equals(type)) cs=new CashReturn(basePrice,returnPrice);
}
}
//客户端程序
public class program{
public static void main(String[] args){
boolean flag=true;
String list="";
Double totalPrice=0.00;
while(flag){
scanner scan=new Scanner(System.in);
System.out.println("输入单价:");
String price=scan.nextLine();
scan=new Scanner(System.in);
System.out.println("输入数量:");
String num=scan.nextLine();
scan=new Scanner(System.in);
System.out.println("输入折扣类型(1无折扣 2打折 3满减):");
String type=scan.nextLine();
double discount=0.0d;
double basePrice=0;
double returnPrice=0;
if("2".equals(type)){
Scan=new Scanner(System.in);
System.out.println("输入折扣:");
discount=Double.parseDouble(scan.nextLine());
}
if("3".equals(type)){
scan=new Scanner(System.in);
System.out.println("返回基础金额:");
basePrice=Double.parseDouble(scan.nextLine());
scan=new Scanner(System.in);
System.out.println("返现金额:");
returnPrice=Double.parseDouble(scan.nextLine());
}
Double xiaoji=Double.parseDouble(pric。e)*Integer.parseInt(num);
CashSuper cs=CashAcceptFactory.createCashAccept(type,discount,basePrice,returnPrice); //类名调用静态方法
double xiaoji=cs.accpetCash(xianjin);
list+="单价:"+price+",数量:"+num+",折扣:"+discount+",小计:"+xiaoji+"\n";
totalPrice+=xiaoji;
if(totalPrice>10){
flag=false;
}
}
System.out.println(list);
System.out.println("总价:"+totalPrice);
}
}
6.简单工厂模式的缺陷
简单工厂模式只是解决对象的创建问题,虽然工厂可能已经包括了所有的收费方式,但商场可能经常地更改打折额度和返利额度,每次维护或扩展收费方式都要改动这个工厂,以致代码需要重新编译部署
不符合开闭原则,所以不是最好地办法。
原因是因为现金收取工厂与具体收费类是紧耦合的,需要改进成现金收取工厂中不要出现具体收费类,
而且现金工厂实际是现金收取控制类,可以用收费类的父类来代替具体收费类,并为其传入具体收费方式对象。
代码如下
//现金收取控制类
class CashContext{
private CashSuper cs; //声明一个现金收费父类对象
public CashContext(CashSuper csuper){
//通过构造方法,传入具体的收费策略对象(正常
打折或返利)
this.cs=csuper; }
public double GetResult(double money){
//根据不同收费策略获得合计结果
return cs.acceptCash(money); }
}
//改造后的客户端代码
public class program{
public static void main(String[] args){
boolean flag=true;
String list="";
Double totalPrice=0.00;
while(flag){
Scanner scan=new Scanner(System.in);
System.out.println("输入单价:");
String price=scan.nextLine();
scan=new Scanner(System.in);
System.out.println("输入数量:");
String num=scan.nextLine();
scan=new Scanner(System.in);
System.out.println("输入折扣类型(1无折扣2打折3满减):");
String type=scan.nextLine();
double discount=0.0d;
double basePrice=0;
double returnPrice=0;
CashSuper cs=null; //改造加入的
if("1".equals(type))cs=new CashNormal();
else
if("2".equals(type)){
scan=new Scanner(System.in);
System.out.println("输入折扣:");
discount=Double.parseDouble(scan.nextLine());
cs=new CashRebate(discount);
}
else if("3".equals(type)){
scan=new Scanner(System.in);
System.out.println("返现基础金额:");
basePrice=Double.parseDouble(scan.nextLine());
scan=new Scanner(System.in);
System.out.println("返现金额:");
returnPrice=Double.parseDouble(scan.nextLine());
cs=new CashReturn(basePrice,returnPrice);
}
Double xianjin=Double.parseDouble(price)*Integer.parse(num);
CashContext cc=new CashContext(cs);
//将相应的策略对象作为参数传入CashContext构造函数中
double xiaoji=cc.GetResult(xianjin);
list+="单价:"+price+",数量:"+num+",折扣:"+discount+",小计:"+xiaoji+"\n";
totalPrice+=xiaoji;
if(totalPrice>10){
flag=false;
}
}
System.out.println(list);
System.out.println("总价:"+totalPrice);
}
}
策略模式下加入新的方法
只需要增加新的方法类
以及修改客户端即可
7. 简单工厂模式和策略模式
简单工厂模式:传条件进工厂类,工厂类就会返回一个对象给调用者,供调用者使用——最终给用户使用的是工厂返回的类
策略模式:创建一个Context类,(可以看作是工厂模式中工厂类的替代品)的对象context,传一个要使用的策略实例对象A个context,然后使用context调用A中的某些方法——最终给用户的是Context类。
8.策略模式的优缺点
策略类之间可以自由切换(由于策略类都实现一个接口)
避免使用多重条件选择语句,充分体现面向对象设计思想
扩展性良好,增加一个新的策略只需要添加一个具体的策略类,不需要改变原有的代码,符合“开闭原则”
缺点:
把分支判断又放回到客户端,需要改变需求算法时,还是要改变客户端程序
缺乏工厂模式的优势,客户端必须知道所有策略类,并自行决定使用哪一个策略类。
策略类增多
9.策略与简单工厂结合
针对策略模式的缺点:分支判断在客户端,改变算法时,要更改客户端的程序,意味着暴露了所有具体策略类
解决:其他不变,改变CashContext类,把分支判断放到环境角色(CashContext 类)中
class CashContext{
private CashSuper cs=null;//声明一个现金收费父类对象
public CashContext()//注意构造函数的参数不再是一个具体策略对象
{
Scanner scan=new Scanner(System.in);
System.out.println("输入折扣类型(1无折扣2打折3满减):");
String type=scan.nextLine();
double discount=0.0d;
double basePrice=0;
double returnPrice=0;
if("1".equals(type)) cs=new CashNormal(); //此处不同
else{ //将实例化具体策略的过程移到Context类中,简单工厂的应用
if("2".equals(type)){
scan=new Scanner(System.in);
System.out.println("输入折扣:");
discount=Double.parseDouble(scan.nextLine());
cs=new CashRebate(discount); //此处不同
}else
if("3".equals(type)){
scan=new Scanner(System.in);
System.out.println("返现基础金额:");
basePrice=Double.parseDouble(scan.nextLine());
scan=new Scanner(System.in);
System.out.println("返现金额:");
returnPrice=Double.parseDouble(scan.nextLine());
cs=new CashReturn(basePrice,returnPrice); //**此处不同**
}
}
public double GetResult(double money){ return cs.acceptCash(money); }
}
//客户端
public class program{
public static void main(String[] args){
boolean flag=true;
String list="";
Double totalPrice=0.00;
while(flag){
Scanner scan=new Scanner(System.in);
System.out.println("输入单价:");
String price=scan.nextLine();
scan=new Scanner(System.in);
System.out.println("输入数量:");
String price=scan.nextLine();
Double xianjin=Double.parseDouble(price)*Integer.parseInt(num);
CashContext cc=new CashContext(); //**此处不同**
double xiaoji=cc.GetResult(xianjin); //
list+="单价:"+price+",数量:"+num+",小计:"+xiaoji+"\n";
totalPrice+=xiaoji;
if(totalPrice>10){ flag=false; } //标志可根据需要更改
System.out.println(list);
System.out.println("总价:"+totalPrice);
}
}