工廠模式
案例說明:
一個披薩的項目:要便於披薩種類的擴展,要便於維護
- 披薩的種類很多(比如 GreekPizz、CheesePizz 等)
- 披薩的製作有 prepare,bake, cut, box
- 完成披薩店訂購功能
案例分別使用四種方式去實現:
點擊跳轉1.傳統方法
2.簡單工廠模式
3.工廠方法模式
4.抽象工廠模式
利用傳統方法完成此案例:
設計思路:
1.設計一個抽象Pizza類,把準備原材料的方法做成抽象方法
2.烹飪 裁剪 打包等方法在抽象類中實現
3.設計GreekPizz CheesePizz 繼承抽象類
4.設計訂單類,創建訂單時需要得到 pizza 的名稱,通過判斷不同名稱,產生不同pizza對象。
5.編寫商店類,產生訂單。
代碼實現:
Pizza抽象類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public abstract class Pizza {
protected String name;
//準備原材料,不同披薩原材料不同
public abstract void prepare();
public void setName(String name){
this.name=name;
}
public void bake() { System.out.println(name + " baking;");}
public void cut() { System.out.println(name + " cutting;" );}
public void box() { System.out.println(name + " boxing;");}
}
Cheese Pizza類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class CheesePizza extends Pizza {
@Override
public void prepare() {
System.out.println("給製作奶酪披薩準備原材料...");
}
}
Greek Pizza類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class GreekPizza extends Pizza {
@Override
public void prepare() {
System.out.println("給製作希臘披薩準備原材料...");
}
}
訂單類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class OrderPizza {
public OrderPizza() {
Pizza pizza = null;
String orderName;
do {
orderName = gettype();
if (orderName.equals("greek")) {
pizza = new GreekPizza();
pizza.setName("希臘披薩 ");
} else if (orderName.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName("奶酪披薩 ");
} else {
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
private String gettype() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
超市類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class PizzaStore {
public static void main(String[] args) {
new OrderPizza();
}
}
結果截圖:
傳統的方式的優缺點:
- 優點是比較好理解,簡單易操作。
- 缺點是違反了設計模式的ocp原則,即對擴展開放,對修改關閉。即當我們給類增加新功能的時候,儘量不修改代碼,或者儘可能少修改代碼.
- 比如我們這時要新增加一個Pizza的種類(Pepper披薩),我們需要做如下修改.
新加胡椒披薩類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class PepperPizza extends Pizza {
@Override
public void prepare() {
System.out.println("爲胡椒披薩準備原材料...");
}
}
訂單類修改:
else if (orderName.equals("pepper")){
pizza = new PepperPizza();
pizza.setName("新加胡椒披薩 ");
}
改進傳統模式分析:
分析:修改代碼可以接受,但是如果我們在其它的地方也有創建Pizza的代碼,就意味
着,也需要修改,而創建Pizza的代碼,往往有多處。
思路:把創建Pizza對象封裝到一個類中,這樣我們有新的Pizza種類時,只需要修改該類就可,其它有創建到Pizza對象的代碼就不需要修改了.-> 簡單工廠模式
簡單工廠模式:
基本介紹:
- 簡單工廠模式是屬於創建型模式,是工廠模式的一種。簡單工廠模式是由一
個工廠對象決定創建出哪一種產品類的實例。簡單工廠模式是工廠模式家族
中最簡單實用的模式 - 簡單工廠模式:定義了一個創建對象的類,由這個類來封裝實例化對象的行
爲(代碼) - 在軟件開發中,當我們會用到大量的創建某種、某類或者某批對象時,就會
使用到工廠模式.
簡單工廠類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class SimpleFactory {
public Pizza createPizza(String orderName){
Pizza pizza = null;
System.out.println("使用簡單工廠模式..");
if (orderName.equals("greek")) {
pizza = new GreekPizza();
pizza.setName("希臘披薩 ");
} else if (orderName.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName("奶酪披薩 ");
}else if (orderName.equals("pepper")){
pizza = new PepperPizza();
pizza.setName("新加胡椒披薩 ");
}
return pizza;
}
}
訂單類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class OrderPizza {
//定義一個簡單工廠對象
SimpleFactory simpleFactory;
Pizza pizza =null;
//構造器
public OrderPizza(SimpleFactory simpleFactory) {
setFactory(simpleFactory);
}
public void setFactory(SimpleFactory simpleFactory){
String orderName="";
do {
orderName = gettype();
pizza = simpleFactory.createPizza(orderName);
if (pizza !=null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.cut();
}else{
System.out.println("訂單錯誤....");
}
}while (true);
}
private String gettype() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
看一個新的需求
披薩項目新的需求:客戶在點披薩時,可以點不同口味的披薩,比如 北京的奶酪pizza、北京的胡椒pizza 或者是倫敦的奶酪pizza、倫敦的胡椒pizza。
思路1
使用簡單工廠模式,創建不同的簡單工廠類,比如BJPizzaSimpleFactory、
LDPizzaSimpleFactory 等等.從當前這個案例來說,也是可以的,但是考慮到項目的
規模,以及軟件的可維護性、可擴展性並不是特別好
思路2
使用工廠方法模式
工廠方法模式
工廠方法模式介紹:
工廠方法模式設計方案:將披薩項目的實例化功能抽象成抽象方法,在不同的口味點
餐子類中具體實現。
工廠方法模式:定義了一個創建對象的抽象方法,由子類決定要實例化的類。工廠方
法模式將對象的實例化推遲到子類。
披薩超市類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class PizzaStore {
public static void main(String[] args) {
new BJOrderPizza();
}
}
北京披薩訂單類繼承抽象類:
先去運行父類的構造方法
/**
* @author 孫一鳴 on 2020/2/5
*/
public class BJOrderPizza extends OrderPizza{
@Override
Pizza createPizza(String orderType) {
Pizza pizza=null;
if(orderType.equals("cheese")){
pizza=new BJCheesePizza();
}else if (orderType.equals("pepper")){
pizza =new BJPepperPizza();
}
return pizza;
}
}
倫敦披薩訂單類繼承父類抽象類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class LDOrderPizza extends OrderPizza{
@Override
Pizza createPizza(String orderType) {
Pizza pizza=null;
if(orderType.equals("cheese")){
pizza=new LDCheesePizza();
}else if (orderType.equals("pepper")){
pizza =new LDPepperPizza();
}
return pizza;
}
}
披薩訂單抽象類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public abstract class OrderPizza {
abstract Pizza createPizza(String orderType);
public OrderPizza(){
Pizza pizza=null;
String orderType;
do {
orderType =gettype();
pizza=createPizza(orderType);//抽象方法,由工廠子類實現
//輸出製作過程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}while (true);
}
private String gettype() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
北京奶酪披薩類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class BJCheesePizza extends Pizza {
@Override
public void prepare() {
setName("北京奶酪披薩");
System.out.println("給北京奶酪披薩準備原料...");
}
}
北京胡椒披薩類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class BJPepperPizza extends Pizza{
@Override
public void prepare() {
setName("北京胡椒披薩");
System.out.println("給北京胡椒披薩準備原料...");
}
}
倫敦奶酪披薩類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class LDCheesePizza extends Pizza {
@Override
public void prepare() {
setName("倫敦奶酪披薩");
System.out.println("給倫敦奶酪披薩準備原料...");
}
}
倫敦胡椒披薩類:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class LDPepperPizza extends Pizza{
@Override
public void prepare() {
setName("倫敦胡椒披薩");
System.out.println("給倫敦胡椒披薩準備原料...");
}
}
抽象工廠模式
基本介紹:
- 抽象工廠模式:定義了一個interface用於創建相關或有依賴關係的對象簇,而無需指明具體的類
- 抽象工廠模式可以將簡單工廠模式和工廠方法模式進行整合。
- 從設計層面看,抽象工廠模式就是對簡單工廠模式的改進(或者稱爲進一步的抽象)。
- 將工廠抽象成兩層,AbsFactory(抽象工廠) 和 具體實現的工廠子類。程序員可以
根據創建對象類型使用對應的工廠子類。這樣將單個的簡單工廠類變成了工廠簇,更利於代碼的維護和擴展。
抽象工廠模式的抽象層 接口
//一個抽象工廠模式的抽象層 接口
public interface AbcFactory {
//讓下面的工廠子類具體實現
public Pizza createPizza(String oederType);
}
北京披薩工廠:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class BJFactory implements AbcFactory{
@Override
public Pizza createPizza(String orderType) {
System.out.println("這是抽象工廠模式..");
Pizza pizza=null;
if(orderType.equals("cheese")){
pizza=new BJCheesePizza();
}else if (orderType.equals("pepper")){
pizza =new BJPepperPizza();
}
return pizza;
}
}
倫敦披薩工廠:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class LDFactory implements AbcFactory{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza=null;
if(orderType.equals("cheese")){
pizza=new LDCheesePizza();
}else if (orderType.equals("pepper")){
pizza =new LDPepperPizza();
}
return pizza;
}
}
披薩訂單 :
/**
* @author 孫一鳴 on 2020/2/5
*/
public class OrderPizza {
AbcFactory factory;
public OrderPizza(AbcFactory factory) {
setFactory(factory);
}
public void setFactory(AbcFactory factory){
Pizza pizza=null;
String orderName="";
this.factory = factory;
do {
orderName = gettype();
pizza = factory.createPizza(orderName);
if (pizza !=null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.cut();
}else{
System.out.println("訂單錯誤....");
break;
}
}while (true);
}
private String gettype() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
披薩商店:
/**
* @author 孫一鳴 on 2020/2/5
*/
public class PizzaStore {
public static void main(String[] args) {
//new OrderPizza(new BJFactory());
new OrderPizza(new LDFactory());
}
}
工廠模式小結
- 工廠模式的意義
將實例化對象的代碼提取出來,放到一個類中統一管理和維護,達到和主項目的
依賴關係的解耦。從而提高項目的擴展和維護性。 - 三種工廠模式 (簡單工廠模式、工廠方法模式、抽象工廠模式)
- 設計模式的依賴抽象原則
創建對象實例時,不要直接 new 類, 而是把這個new 類的動作放在一個工廠的方法
中,並返回。有的書上說,變量不要直接持有具體類的引用。
不要讓類繼承具體類,而是繼承抽象類或者是實現interface(接口)
不要覆蓋基類中已經實現的方法。