1. 程式人生 > >工廠模式和策略模式

工廠模式和策略模式

一、工廠模式

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 {@Overridepublic double getResult() {return

getNumberA() + getNumberB();}}class OperationSub extends Operation {@Overridepublic double getResult() {return getNumberA() - getNumberB();}}class OperationMul extends Operation {@Overridepublic double getResult() {return getNumberA() * getNumberB();}}class OperationDiv extends Operation {@Overridepublic 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{@Overridepublic 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{@Overridepublic Operation createOperation() {return new OperationAdd();}}class SubFactory implements IFactory{@Overridepublic Operation createOperation() {return new OperationSub();}}class MulFactory implements IFactory{@Overridepublic Operation createOperation() {return new OperationMul();}}class DivFactory implements IFactory{@Overridepublic 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{@Overridepublic void insert(User user) {System.out.println("Sqlserver 插入User表");}@Overridepublic User getUser(int id) {System.out.println("Sqlserver 查詢User表");        return null;}}

public class AccessUser implements IUser {@Overridepublic void insert(User user) {System.out.println("Access 插入User表");}@Overridepublic User getUser(int id) {System.out.println("Access 查詢User表");        return null;}}

對於product

public class SqlserverProduct implements IProduct {@Overridepublic void insert(Product product) {System.out.println("Sqlserver 插入Product表");}@Overridepublic Product getProduct(int id) {System.out.println("Sqlserver 查詢Product表");        return null;}}

public class AccessProduct implements IProduct {@Overridepublic void insert(Product product) {System.out.println("Access 插入Product表");}@Overridepublic Product getProduct(int id) {System.out.println("Access 查詢Product表");        return null;}}

建立抽象工廠介面

public interface IFactory {    IUser CreateUser();IProduct CreateProduct();}

建立sqlserverFactory

public class SqlaerverFactory implements IFactory {@Overridepublic IUser CreateUser() {return new SqlserverUser();}@Overridepublic IProduct CreateProduct() {return new SqlserverProduct();}}

建立AccessFactory

public class AccessFactory implements IFactory {@Overridepublic IUser CreateUser() {return new AccessUser();}@Overridepublic 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);}}

只需更改一句就能移植到其他資料庫。

執行結果為:

 

當修改後

 

二、策略模式

商場經常會有不同的活動,加錢也會發生變化,如打八折和滿30080現在為商城設計一個軟體,輸入商品價格,根據不同的優惠返回最後要付的值,這種使用一系列不同演算法的軟體可以用策略模式進行設計。

先定義所有演算法的公告介面CashSuper

public interface CashSuper {double acceptCashh(double money);} 

然後建立封裝的具體的演算法類

class CashNormal implements CashSuper{@Overridepublic double acceptCashh(double money) {return money;}}class CashRebate implements CashSuper{private double moneyRebate=1.0;    public CashRebate(double moneyRebate){this.moneyRebate=moneyRebate;}@Overridepublic 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;}@Overridepublic 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));}}

運算結果為: