文章目錄
簡單工廠
簡單工廠具體來說不算一種模式,
而是一種設計思想————將業務邏輯和界面邏輯分離,即服務端和客戶端分離
在不需要客戶端進行修改,在服務端修改增加產品類即可。
具體的做法:
1.創建工廠類作爲父類,產品類作爲工廠類子類,具體產品類作爲產品類子類
2.工廠類根據客戶端選擇參數的不同,建立創建產品函數返回產品對象,產品類寫出方法,具體產品類作爲具體實現
服務端代碼:
服務端
public class Factory{
// 工廠製作**相應的產品對象**
public FoodProduct createProduct(int choose){
FoodProduct food = null;
switch (choose){
case 1:
food = new Hamburger();
break;
case 2:
food = new Rice();
break;
default:
food = null;
break;
}
return food;
}
}
// 食物產品確定需要的動作
public class FoodProduct extends Factory{
private double price;
public double getPrice() {return price;}
public void setPrice(double price) {
this.price = price;
}
public void showInfo(){};
}
// 具體的漢堡產品實現具體的操作,比如實現價格顯示,和價格初始化
public class Hamburger extends FoodProduct{
// 價格初始化
public Hamburger(){
this.setPrice(18.0);
}
// 具體實現了展現信息
@Override
public void showInfo(){
System.out.println("漢堡的價格爲" + this.getPrice());
}
}
//具體的米飯產品實現
public class Rice extends FoodProduct{
// 價格初始化
public Rice(){
this.setPrice(38.0);
}
// 具體實現了展現信息
@Override
public void showInfo(){
System.out.println("米飯的價格爲" + this.getPrice());
}
}
客戶端的代碼:
public class Main{
public static void main(String[] args){
Factory hamburger = new Factory();
FoodProduct food;
//客戶端輸入具體的參數,就能獲得相應的產品對象
food = hamburger.createProduct(1);
}
}
UML圖如下:
優點:
1.實現了對象創建和使用的分離(即業務邏輯和界面邏輯分離)。
2.客戶端無需知道所創建的具體產品類的類名,只需知道具體產品類所對應的參數即可。
3.通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。
缺點我就不說了,因爲很明顯,這是僅僅是一個經常要用到的思想,但是真正的工程不可能這麼簡單的,缺點很多也很致命,這個算不上設計模式。
工廠方法模式
工廠方法和簡單工廠最大的區別就是在於製造了將原本的工廠抽象成工廠接口,具體的對象創建延遲到下面具體的工廠子類來實現,使增加新的工廠產品時不用修改代碼,只需增加類即可。
工廠模式具體做法:
1,定義一個用於創建對象的接口,但是讓子類決定將哪一個類實例化。
2…工廠子類根據客戶端選擇參數的不同,建立創建產品函數返回產品對象,產品類寫出方法,具體產品類作爲具體實現。
服務端
// 抽象工廠接口
public interface Factory{
public FoodProduct createProducts();
}
// 兩個具體的生產產品工廠
public class HamburgerProductFactory implements Factory {
// 工廠製作**相應的產品對象**
public FoodProduct createProducts(){
return new Hamburger();
}
}
public class RiceProductFactory implements Factory {
// 工廠製作**相應的產品對象**
public FoodProduct createProducts(){
return new Rice();
}
}
// 食物產品確定需要的動作
public class FoodProduct{
private double price;
public double getPrice() {return price;}
public void setPrice(double price) {
this.price = price;
}
public void showInfo(){};
}
// 具體的漢堡產品實現具體的操作,比如實現價格顯示,和價格初始化
public class Hamburger extends FoodProduct{
// 價格初始化
public Hamburger(){
this.setPrice(18.0);
}
// 具體實現了展現信息
@Override
public void showInfo(){
System.out.println("香辣漢堡的價格爲" + this.getPrice());
}
}
//具體的米飯產品實現
public class Rice extends FoodProduct{
// 價格初始化
public Rice(){
this.setPrice(38.0);
}
// 具體實現了展現信息
@Override
public void showInfo(){
System.out.println("米飯的價格爲" + this.getPrice());
}
}
客戶端的代碼:
public class Main{
public static void main(String[] args){
// 客戶端當要創建漢堡時,去用多態實例化一個漢堡工廠對象
Factory hamburger = new HamburgerProductFactory();
//客戶端選擇對應的創建函數,能創建相應的產品對象
FoodProduct food = hamburger.createProducts();
}
}
UML圖如下:
簡單工廠 VS 工廠方法
簡單工廠的好處就是實現對象創建與使用的分離,而這點工廠方法也通過它的做法做到了
所以簡而言之,工廠方法是簡單工廠的升級版。
但是簡單工廠的問題,工廠方法有全部避免了嗎??
1.首先簡單工廠違背的開放——封閉原則,即對擴展開放,對修改封閉
——工廠方法通過創建了工廠接口,將創建對象實例化,延遲到了子類,當需要增加新的產品時,只需增加類即可,不需要修改原先的代碼,滿足了開放–封閉。
——但是同時工廠方法也暴露了一個很重要的問題,就是簡單工廠的邏輯判斷從工廠類轉移到了客戶端,當我需要米飯類產品時,就需要修改客戶端了!!(反射可以優化)
2.同時工廠方法還有一個缺點:每次新增產品,產品類都需要創建對應工廠類,雖然滿足了開放–封閉原則,但是增加了系統的開銷。
同時爲了引出第三個抽象工廠,我們需要知道產品等級結構和產品族的概念:
產品等級結構:產品等級結構即產品的繼承結構
產品族:同一個工廠生產的,位於不同產品等級結構中的一組產品
這張圖很好的解釋了產品族和產品等級結構,
例如上面代碼的food作爲一個產品,那麼構成它的漢堡,米飯等等即爲它的產品族,
而香辣漢堡,雞肉漢堡,牛肉漢堡這些相似的產品則互組成產品等級結構,
作爲子類繼承父類漢堡
抽象工廠與工廠方法和簡單工廠有一個很大的不同就是:多了產品等級結構,更加的複雜,也更符合現實的生活真實情況。
抽象工廠
理論抽象工廠UML圖
之前寫好過一個抽象工廠的,代碼先po出來
// 抽象工廠接口
public interface FoodAbstractFactory {
Rice createRice(int num); //生產米飯
Hamburgers createHamburgers(int num); //生產漢堡
Noodles createNoodles(int num); // 生產面
}
具體工廠
// 具體工廠A香辣工廠
public class ConFoodFactory_Spicy implements FoodAbstractFactory {
/**
* 生產漢堡
* */
public Hamburgers createHamburgers(int num){
//香辣雞腿堡
return new Hamburgers_Spicy(num);
}
/**
* 生產米飯
* */
public Rice createRice(int num) {
return new Rice_Spicy(num);
}
/**
* 生產麪條
* */
public Noodles createNoodles(int num) {
//紅燒牛肉麪
return new Noodles_Spicy(num);
}
}
// 具體的
public class ConFoodFactory_Beef implements FoodAbstractFactory {
/*
* 生產漢堡
* */
public Hamburgers createHamburgers(int num){
//香辣雞腿堡
return new Hamburgers_Beef(num);
}
/**
* 生產米飯
* */
public Rice createRice(int num) {
return new Rice_Beef(num);
}
/**
* 生產麪條
* */
public Noodles createNoodles(int num) {
//紅燒牛肉麪
return new Noodles_Beef(num);
}
}
// 抽象物品信息類
public abstract class foodCommonInfo {
private int num; //數量
private double price; //價格
//計算餐品總價
public double totalPrice() {
//return this.num * this.price;
return num * price;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
// 多繼承接口
public interface SingleFood {
void showOrderInfo();
void showMenuInfo();
}
public interface SingleFoodMenu extends SingleFood{
void showMenuInfo();
}
public interface SingleFoodOrder extends SingleFood {
void showOrderInfo();
}
各類產品類
// 漢堡產品類
public class HamburgersProduct extends foodCommonInfo implements SingleFood{
@Override
public void showOrderInfo() {
System.out.println("漢堡的價格——————————————" + this.getPrice());
}
@Override
public void showMenuInfo() {
System.out.println("漢堡類------------------------------------------------");
}
}
// 麪條產品類
public class NoodlesProduct extends foodCommonInfo implements SingleFood{
@Override
public void showOrderInfo() {
System.out.println("麪條的價格爲————————" + this.getPrice());
}
@Override
public void showMenuInfo() {
System.out.println("麪條類------------------------------------------------");
}
}
// 米飯產品類
public class RiceProduct extends foodCommonInfo implements SingleFood{
@Override
public void showOrderInfo() {
System.out.println("price");
}
@Override
public void showMenuInfo() {
System.out.println("米飯類------------------------------------------------");
}
}
具體個類產品類的實現
// 香辣漢堡的具體實現
public class Hamburgers_Spicy extends HamburgersProduct {
// 有參構造方法
public Hamburgers_Spicy(int num){
this.setNum(num);
this.setPrice(18.0);
}
public Hamburgers_Spicy(){
this.setPrice(18.0);
}
@Override
public void showOrderInfo(){
System.out.println("訂購了香辣漢堡的價格爲" + this.getPrice() + "元————" +
"數量爲:" + this.getNum() + "個————" +
"總計:" + this.totalPrice() + "元");
}
@Override
public void showMenuInfo() {
System.out.println("1.香辣漢堡—————————————————————" + this.getPrice() + "元");
}
}
// 牛肉漢堡的具體實現
public class Hamburgers_Beef extends HamburgersProduct {
// 有參構造方法
public Hamburgers_Beef(int num){
this.setNum(num);
this.setPrice(28.0);
}
public Hamburgers_Beef(){
this.setPrice(28.0);
}
@Override
public void showOrderInfo(){
System.out.println("訂購了牛肉漢堡的價格爲" + this.getPrice() + "元————" +
"數量爲:" + this.getNum() + "個————" +
"總計:" + this.totalPrice() + "元");
}
@Override
public void showMenuInfo() {
System.out.println("2.牛肉漢堡—————————————————————" + this.getPrice() + "元");
}
}
在這裏我只列出漢堡具體類,米飯和麪條大同小異,太長不列出來了。
點餐的客戶代碼:
// 客戶client
public class Manangers {
//抽象工廠
private FoodAbstractFactory factory_con;
//構造方法將抽象工廠傳入
public Manangers(FoodAbstractFactory factory_con) {
this.factory_con = factory_con;
}
/**
* 訂購食物
*/
//漢堡
public double orderHamburgers(int num) {
//獲得不同種類的漢堡 多態父類引用指向子類對象
HamburgersProduct hamburger = factory_con.createHamburgers(num);
//輸出訂購信息
hamburger.showOrderInfo();
//返回總價
return hamburger.totalPrice();
}
//麪條
public double orderNoodles(int num) {
//獲得麪條
NoodlesProduct frenchFries = factory_con.createNoodles(num);
//輸出訂購信息
frenchFries.showOrderInfo();
//返回總價
return frenchFries.totalPrice();
}
//米飯
public double orderRices(int num) {
//獲得不同種類的米飯
RiceProduct rice = factory_con.createRice(num);
//輸出訂購信息
rice.showOrderInfo();
//返回總價
return rice.totalPrice();
}
}
菜單展示代碼
public class Menus implements SingleFoodMenu{
@Override
public void showMenuInfo() {
HamburgersProduct hamburgerskind = new HamburgersProduct();
HamburgersProduct hamburgers1 = new Hamburgers_Spicy();
HamburgersProduct hamburgers2 = new Hamburgers_Beef();
RiceProduct ricekind = new RiceProduct();
RiceProduct rice2 = new Rice_Beef();
RiceProduct rice1 = new Rice_Spicy();
NoodlesProduct noodleskind = new NoodlesProduct();
NoodlesProduct noodles2 = new Noodles_Beef();
NoodlesProduct noodles1 = new Noodles_Spicy();
System.out.println("-----------------------單品菜單------------------------");
hamburgerskind.showMenuInfo();
hamburgers1.showMenuInfo();
hamburgers2.showMenuInfo();
System.out.println("------------------------------------------------------");
noodleskind.showMenuInfo();
noodles1.showMenuInfo();
noodles2.showMenuInfo();
System.out.println("------------------------------------------------------");
ricekind.showMenuInfo();
rice1.showMenuInfo();
rice2.showMenuInfo();
System.out.println("------------------------------------------------------");
}
@Override
public void showOrderInfo() {}
}
客戶端代碼:
// 客戶端
public class Main {
public static void main(String[] args) {
Menus menus = new Menus();
menus.showMenuInfo();
//建造訂購者
// 建造香辣工廠
FoodAbstractFactory factory_spicy = new ConFoodFactory_Spicy();
Manangers order_spicy = new Manangers(factory_spicy);
// 訂購商品
double price1 = order_spicy.orderNoodles(2);
double price2 = order_spicy.orderRices(3);
double price3 = order_spicy.orderHamburgers(1);
System.out.println( "餐品總價爲" + (price1 + price2 + price3) + "元");
}
}
具體的結果展示:
抽象工廠模式更好的可以展示多種多樣的產品,同時開放封閉原則還能得到很好的體現
UML圖
PS:抽象工廠的具體工廠是生產的一個產品族還是產品等級結構是可以變的!!!!!
抽象工廠可以新增加產品族和產品等級結構,但是修改程度不同
①前提:具體工廠是抽取產品等級結構元素設計
例如我上述代碼的香辣工廠,牛肉工廠
增加產品等級結構------符合開閉原則:
對於增加新的產品等級結構,抽象工廠模式很好地支持了開閉原則,只需要增加具體產品等級結構並對應增加一個新的具體工廠,對已有代碼無須做任何修改。
增加新的產品族------不符合開閉原則:
增加新的產品族:對於增加新的產品族,例如我現在新增米線族,需要修改所有的工廠角色,包括抽象工廠類,在所有的工廠類中都需要增加生產新產品的方法,違背了開閉原則。
②前提:具體工廠是抽取產品族元素設計
例如漢堡工廠,米飯工廠
增加產品族------符合開閉原則:
對於增加新的產品族,抽象工廠模式很好地支持了開閉原則,只需要增加具體產品等級結構並對應增加一個新的具體工廠,對已有代碼無須做任何修改。
增加新的產品等級結構------不符合開閉原則:
增加新的產品等級結構:對於增加新的產品等級結構,例如我現在新增青椒族,需要修改所有的工廠角色,包括抽象工廠類,在所有的工廠類中都需要增加生產新產品的方法,違背了開閉原則。
PS:這兩個前提是我自己最近悟出來的,可能有對可能有錯歡迎討論,但是我覺着這樣子變通,纔可以讓抽象工廠更加的靈活,不一定是網上說的一種情況。
最後由於客戶端也需要的修改,我們可以用反射來優化。