每个软件开发人员都应该知道的5种设计模式
通常設計模式是用于解決問題的模板,可以在多種不同的情況下使用,但它并不是一個可以直接轉換為代碼的設計,但確實開發者奠定軟件是否成功的基礎。
有一些設計模式是每個開發人員都應該了解的,包括它應該在什么地方和什么時候使用,今天,就和大家討論一下每個軟件開發人員都應該知道5種重要的設計模式:
?
1、單例模式
這是最常用和最常見的設計模式,幾乎每個應用程序都需要用到單例模式,這種模式涉及到一個單一的類,該類負責創建自己的對象,當你需要一個對象來協調跨系統的操作時,單例模式是很好的解決方式。
顧名思義,模式用于保證一個類僅有一個實例。需要聲明一個私有構造函數,以防止從類外部實例化。另外,它需要聲明一個singleton類型的靜態字段。
?
public?class?SingletonDemo?{private?static?SingletonDemo?instance?=?null;private?SingletonDemo()?{}public?static?SingletonDemo?getInstance()?{if(instance?==?null)?{instance?=?new?SingletonDemo();}return?instance;} }?
上面的代碼中的getInstance()方法在運行時只創建這個類的一個實例,首選的場景:類只有一個實例,包括緩存、線程池和注冊表。
?
單例模式的getInstance()方法并不是線程安全的。它可以被實例化不止一次,可以通過在方法上加同步調用來解決,但是這會使方法變慢。
?
?
2、工廠模式(Factory Pattern)
?
這里單詞factory說的是工廠的意思,同樣的軟件工廠生產對象,它只是通過調用工廠方法,而不是調用特定類的構造函數來實現這一點。通常,對象創建的過程如下:
?
DemoClass?demoClassObject?=?new?DemoClass();?
上述方法的問題是代碼使用了具體的對象DemoClass。使用new創建對象也可以,但是它將代碼緊密地耦合到了具體的類。可以通過如下的工廠模式解決該問題:
?
public?interface?Notification{String?getType(); } public?class?Call?implements?Notification{public?String?getType(){return?"call"} } public?class?Message?implements?Notification{public?String?getType(){return?"message"} } public?class?NotificationFactory?{private?static?Map<String,?Notification>?instances;static?{instances?=?new?HashMap<>();instances.put("call",?new?Call());instances.put("message",?new?Message());} public?static?<T?extends?Notification>?T?getNotification(String???type){return?(T)?instances.get(type);?} } Notification?notif?=?NotificationFactory.getNotification("call");?
當一個類無法預料要創建哪種類的對象或是一個類需要由子類來指定創建的對象時,可以考慮使用工廠模式另外,開發人員可能不知道要構造哪種類型,例如在針對基本類型或接口進行編碼時,也可以使用工廠模式。
?
工廠模式可以擴展系統中類的總數。每個具體的類還需要一個具體的對象,但是你可以通過參數化的Factory Method來避免。
?
?
3、建造者模式
?
顧名思義,建造者模式是用于構建對象,有時我們創建的對象可能很復雜,由多個子對象組成,或者需要復雜的構造過程。
?
建造者模式用于逐步構造一個復雜的對象,最后一步將返回該對象。構造對象的過程應該是通用的,以便可以用來創建同一對象的不同表示形式。下面的示例可以幫你更好的理解它:
?
public?class?Product?{private?String?id;private?String?name;private?String?description;private?Double?value;private?Product(Builder?builder)?{setId(builder.id);setName(builder.name);setDescription(builder.description);setValue(builder.value);}public?static?Builder?newProduct()?{return?new?Builder();}public?String?getId()?{return?id;}public?void?setId(String?id)?{this.id?=?id;}public?String?getName()?{return?name;}public?void?setName(String?name)?{this.name?=?name;}public?String?getDescription()?{return?description;}public?void?setDescription(String?description)?{this.description?=?description;}public?Double?getValue()?{return?value;}public?void?setValue(Double?value)?{this.value?=?value;}public?static?final?class?Builder?{private?String?id;private?String?name;private?String?description;private?Double?value;private?Builder()?{}public?Builder?id(String?id)?{this.id?=?id;return?this;}public?Builder?name(String?name)?{this.name?=?name;return?this;}public?Builder?description(String?description)?{this.description?=?description;return?this;}public?Builder?value(Double?value)?{this.value?=?value;return?this;}public?Product?build()?{return?new?Product(this);}} } Product?product?=?Product.newProduct().id(1l).description("TV?46'").value(2000.00).name("TV?46'").build();?
建造者模式非常類似于工廠模式,他們的主要區別在于,當你需要構建對象時,建造者模式會非常有幫助。
?
在建造者模式中,代碼行的數量至少增加了一倍,但是在設計靈活性和可讀性方面,建造者模式的優勢又是很明顯的。
?
?
4、適配器模式(Adapter Pattern)
?
這種模式將一個類的接口轉換成另外一個類的的接口,它充當翻譯者的角色,當兩個不說共同語言的領導見面時,通常會有一位口譯員坐在兩者之間,翻譯對話,從而實現交流。
?
interface?Bird? {?//?birds?implement?Bird?interface?that?allows?//?them?to?fly?and?make?sounds?adaptee?interface?public?void?fly();?public?void?makeSound();? } class?Sparrow?implements?Bird? {?//?a?concrete?implementation?of?bird?public?void?fly()?{?System.out.println("Flying");?}?public?void?makeSound()?{?System.out.println("Chirp?Chirp");?}? } interface?ToyDuck? {?//?target?interface?//?toyducks?dont?fly?they?just?make?//?squeaking?sound?public?void?squeak();? } class?PlasticToyDuck?implements?ToyDuck? {?public?void?squeak()?{?System.out.println("Squeak");?}? } class?BirdAdapter?implements?ToyDuck? {?//?You?need?to?implement?the?interface?your?//?client?expects?to?use.?Bird?bird;?public?BirdAdapter(Bird?bird)?{?//?we?need?reference?to?the?object?we?//?are?adapting?this.bird?=?bird;?}public?void?squeak()?{?//?translate?the?methods?appropriately?bird.makeSound();?}? } class?Main? {?public?static?void?main(String?args[])?{?Sparrow?sparrow?=?new?Sparrow();?ToyDuck?toyDuck?=?new?PlasticToyDuck();//?Wrap?a?bird?in?a?birdAdapter?so?that?it?//?behaves?like?toy?duck?ToyDuck?birdAdapter?=?new?BirdAdapter(sparrow);System.out.println("Sparrow...");?sparrow.fly();?sparrow.makeSound();System.out.println("ToyDuck...");?toyDuck.squeak();//?toy?duck?behaving?like?a?bird?System.out.println("BirdAdapter...");?birdAdapter.squeak();? }? }?
如果你有兩個應用程序,其中一個以XML格式輸出,另一個則需要JSON輸入(或其他格式),那么你將需要在兩者之間使用適配器模式來無縫運行。但是適配器不能與Adaptee或Target的子類一起使用。
?
?
5、狀態模式(State Pattern)
?
這種模式有助于我們表示對象的幾種狀態,假設有一個廣播類的對象。它可以處于兩種狀態,即打開或關閉。這些狀態可以用狀態模式表示。
?
在實際應用程序中,對象具有許多狀態,我們可以實現狀態模式以降低系統復雜性,讓我們通過一個廣播示例來理解這一點:
?
public?class?Radio?{private?boolean?on;private?RadioState?state;public?Radio(RadioState?state){this.state?=?state;}public?void?execute(){state.execute(this);}public?void?setState(RadioState?state){this.state?=?state;}public?void?setOn(boolean?on){this.on?=?on;}public?boolean?isOn(){return?on;}public?boolean?isOff(){return?!on;} } public?interface?RadioState?{void?execute(Radio?radio); } public?class?OnRadioState?implements?RadioState?{public?void?execute(Radio?radio){//throws?exception?if?radio?is?already?onradio.setOn(true);} } public?class?OffRadioState?implements?RadioState?{public?void?execute(Radio?radio){//throws?exception?if?radio?is?already?offradio.setOn(false);} } Radio?radio?=?new?Radio(new?OffRadioState());?//initial?status radio.setState(new?OnRadioState()); radio.execute();?//radio?on radio.setState(new?OffRadioState()); radio.execute();?//radio?off?
上面的示例用狀態模式表示無線電的不同狀態。
當我們需要表示對象內部發生變化的幾種狀態時,在不使用狀態模式的情況下,代碼會變得很僵硬,并帶有if-else條件語句。
狀態模式需要編寫許多代碼,根據定義了多少種不同的狀態轉換方法以及對象可能處于多種狀態,這樣就會有數十種甚至更多不同的方法需要編寫。
當然,還有許多其他有用的設計模式,但這是最常用的模式。了解上述模式后,你就可以開始學習其他模式。因為大多數應用程序是通過使用多種設計模式進行構建的
總結
以上是生活随笔為你收集整理的每个软件开发人员都应该知道的5种设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 运维日常 40 个命令汇总
- 下一篇: Linux 系统审计操作行为的 5 种解