-
1 # IT技術圈
-
2 # 良行天下
一、設計模式入門:
1.設計模式是人們在面對同類型軟體工程設計問題所總結出的一些有用經驗。模式不是程式碼,而是某類問題的通用設計解決方案
2.設計模式的本質目的是使軟體工程在維護性、擴充套件性、變化性、複雜度方面成O(N)
3.OOP是原則,設計模式是具體方法、工具
————————————————————————————————————————————
二、策略模式
從文字方面可能我們很難理解,所以我們從實際專案入手
現在假設我們有個“鴨子專案”,首先我們用OOP的角度設計這個專案,找到鴨子中共同的特性抽取在父類中並具體實現,不同的特性不實現,由子類具體實現,好下面看程式碼:
public abstract class Duck {
/**
* 叫聲和游泳為相同的特性抽取並具體實現
*/
public void Quack() {
System.out.println("~~gaga~~");
}
public void swim() {
System.out.println("~~im swim~~");
}
/**
* 外貌為不同的特性設計為抽象的方法,有子類具體實現
*/
public abstract void display();
}
現在我們看它的子類:
public class GreenHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**GreenHead**");
}
}
public class RedHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**RedHead**");
}
}
現在我們可以看到使用OOP可以很好的解決目前的問題,但是我們往往是需求不斷,所以我們現在又來一個新需求:新增會飛的鴨子
好辦啊,我們只要在父類中新增一個新的方法:
public abstract class Duck {
/**
* 叫聲和游泳為相同的特性抽取並具體實現
*/
public void Quack() {
System.out.println("~~gaga~~");
}
public void swim() {
System.out.println("~~im swim~~");
}
/**針對新需求的方法*/
public void Fly() {
System.out.println("~~im fly~~");
}
/**
* 外貌為不同的特性設計為抽象的方法,有子類具體實現
*/
public abstract void display();
}
繼承的問題:對類的區域性改動,尤其超類的區域性改動,會影響其他部分。影響會有溢位效應
好現在我們繼續用OOP的方式去解決,使其子類覆蓋Fly:
public class GreenHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**GreenHead**");
}
/**
* 覆蓋
* */
public void Fly() {
System.out.println("~~no fly~~");
}
}
分析問題:
需要新的設計方式,應對專案的擴充套件性,降低複雜度:
1)分析專案變化與不變部分,提取變化部分,抽象成介面+實現;
2)鴨子哪些功能是會根據新需求變化的?叫聲、飛行…
我們將變化的功能設計成介面,下面看程式碼:
public interface FlyBehavior {
void fly();
}
public interface QuackBehavior {
void quack();
}
來看看新的Duck類:
public abstract class Duck {
/**
* 父類定義行為出來,但是沒有具體例項化
*/
FlyBehavior mFlyBehavior;
QuackBehavior mQuackBehavior;
public Duck() {
}
public void Fly() {
if (mFlyBehavior!=null) {
mFlyBehavior.fly();
}
}
public void Quack() {
if (mQuackBehavior!=null) {
mQuackBehavior.quack();
}
}
/**
* 子類可以透過兩個行為的set方法去動態改變自己的具體行為
*/
public void setmFlyBehavior(FlyBehavior mFlyBehavior) {
this.mFlyBehavior = mFlyBehavior;
}
public void setmQuackBehavior(QuackBehavior mQuackBehavior) {
this.mQuackBehavior = mQuackBehavior;
}
public abstract void display();
}
在去看看子類:
public class RedHeadDuck extends Duck{
public RedHeadDuck() {
mFlyBehavior=new GoodFlyBehavior();
mQuackBehavior=new GaGaQuackBehavior();
}
@Override
public void display() {
System.out.println("redDuck");
}
}
public class GreenHeadDuck extends Duck{
public GreenHeadDuck() {
mFlyBehavior=new BadFlyBehavior();
mQuackBehavior=new GeGeQuackBehavior();
}
@Override
public void display() {
System.out.println("greenDuck");
}
再來看看介面實現類:
public class BadFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("bad fly");
}
}
public class GoodFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("good fly");
}
}
public class NoFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("No fly");
}
}
public class GaGaQuackBehavior implements QuackBehavior{
@Override
public void quack() {
System.out.println("gaga quack");
}
}
public class GeGeQuackBehavior implements QuackBehavior{
@Override
public void quack() {
System.out.println("gege quack");
}
}
public class NoQuackBehavior implements QuackBehavior{
@Override
public void quack() {
System.out.println("No Quack");
}
}
在父類中我們定義好FlyBehavior & QuackBehavior 兩個行為介面,然後在子類構造方法中分別設定對應的具體行為
現在來測試一下:
策略模式:分別封裝行為介面,實現演算法族,超類裡放行為介面物件,在子類裡具體設定行為物件。原則就是:分離變化部分,封裝介面,基於介面程式設計各種功能。此模式讓行為演算法的變化獨立於演算法的使用者
—————————————————————————————————————————————
三、觀察者模式:
跟之前一樣,我們還是透過實際專案入手,之後,這句話我就不重複了,直接從專案開始講解了
現在假設我們有一個需要為A公司實時提供天氣的天氣預報介面專案,好的,首先我們還是以OOP的方式去解決問題,首先我們建立一個天氣臺物件並提供相關方法假設它可以實時為A公司提供天氣資料,下面看程式碼:
public class MeteorologicalStation {
private float pressure;
private float temperature;
private float humidity;
private ACompany company;
public MeteorologicalStation(ACompany company) {
this.company=company;
}
public float getPressure() {
return pressure;
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
/**
* 實時提供天氣情況
* */
public void uploadData(float pressure,float temperature,float humidity){
company.getMeteorologicalStationData(pressure, temperature, humidity);
}
}
ACompany為A公司:
public class ACompany {
public void getMeteorologicalStationData(float pressure, float temperature, float humidity) {
System.out.println("pressure: "+pressure+",temperature: "+temperature+",humidity: "+humidity);
}
}
測試
/**
* 該介面相當於天氣臺管理者,誰想接入我和離開我都必須透過它去管理
* */
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifObserver();
}
/**
* 透過該介面,每個想要接入的公司實現該方法即可。
*/
public interface Observer {
void getMeteorologicalStationData(float pressure,float temperature,float humidity);
}
public class MeteorologicalStation implements Subject {
private float pressure;
private float temperature;
private float humidity;
private ArrayList<Observer> observers;
public MeteorologicalStation(ACompany company) {
observers = new ArrayList<Observer>();
}
public float getPressure() {
return pressure;
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public void uploadData(float pressure, float temperature, float humidity) {
this.pressure = pressure;
this.temperature = temperature;
this.humidity = humidity;
notifObserver();
}
@Override
public void registerObserver(Observer o) {
if (!observers.contains(o)) {
observers.add(o);
}
}
@Override
public void removeObserver(Observer o) {
if (observers.contains(o)) {
observers.remove(o);
}
}
@Override
public void notifObserver() {
for (int i = 0; i < observers.size(); i++) {
Observer observer = observers.get(i);
observer.getMeteorologicalStationData(getPressure(), getTemperature(), getHumidity());
}
}
}
public class ACompany implements Observer{
@Override
public void getMeteorologicalStationData(float pressure,float temperature,float humidity){
System.out.println("A pressure: "+pressure+",temperature: "+temperature+",humidity: "+humidity);
}
}
public class BCompany implements Observer{
@Override
public void getMeteorologicalStationData(float pressure, float temperature, float humidity) {
System.out.println("B pressure: "+pressure+",temperature: "+temperature+",humidity: "+humidity);
}
}
現在只需要實現Observer介面即可。現在我們來測試下:
看到這裡我們已經知道了觀察者模式的好處,下面我們看看java內建的觀察者:
public class MeteorologicalStation extends Observable {
private float pressure;
private float temperature;
private float humidity;
public float getPressure() {
return pressure;
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public void uploadData(float pressure, float temperature, float humidity) {
this.pressure = pressure;
this.temperature = temperature;
this.humidity = humidity;
WeatherData data=new WeatherData(pressure, temperature, humidity);
/**
* setChanged
* 根據有些特定的需求出現的,設定後喚醒才有效,
* 例如我們不需要溫度改變0.5我們也去喚醒客戶,
* 因此這裡我們可以判斷後在設定
* */
this.setChanged();
this.notifyObservers(data);
}
public class WeatherData{
public float pressure;
public float temperature;
public float humidity;
public WeatherData(float pressure, float temperature, float humidity) {
this.pressure = pressure;
this.temperature = temperature;
this.humidity = humidity;
}
}
}
從程式碼中可以看到Observable 是一個類 而不是像我們一樣的Subject的介面,
this.setChanged();
this.notifyObservers(data);
兩個一起使用才有效,下面我們看看A,B公司需要怎麼做:
public class ACompany implements Observer{
@Override
public void update(Observable arg0, Object arg1) {
WeatherData data=(WeatherData) arg1;
System.out.println("A pressure: "+data.pressure+",temperature: "+data.temperature+",humidity: "+data.humidity);
}
public class BCompany implements Observer{
@Override
public void update(Observable o, Object arg) {
WeatherData data=(WeatherData) arg;
System.out.println("B pressure: "+data.pressure+",temperature: "+data.temperature+",humidity: "+data.humidity);
}
}
A,B公司只要實現系統的Observer介面,和我們剛才的設計是一樣的。最後我們在測試一下:
可以看到和我們之前的效果完全一樣
—————————————————————————————————————————————
四、裝飾者模式
咖啡館訂單系統專案:
咖啡種類:Espresso、ShortBlack、LongBlack、Decaf
調料:Milk、Soy、Chocolate
顧客首先選擇咖啡種類,然後在選擇是否需要調料,我們需要描述出顧客選擇的咖啡種類及其調料名稱,及其花費的總價。
好的,現在我們來看一個差的方案:
首先是定義了一個抽象的Drink父類,裡面定義出一個抽象的cost()方法用於返回消費的總價,用setDescription去描述各個消費商品的名稱,使用getDescrption將客戶的消費訂單列印,後面又將大概的客戶消費可能出現的情況一一去列舉出來,但是 由於這個消費情況太多,所以沒有用程式碼去描述,各個消費情況繼承Drink類,實現cost()抽象方法,使用父類的super.getPrice()返回總價,在構造中使用super.setDescriptin()和super.setPrice()分別去設定自己的產品名稱及其價格。圖中我們可以看到加入有許多種情況,我們需要定義太多的類。
好的,我們在來看一個好一點的方案:
從圖中可以看到基本和第一種方案基本類似,只是將調料的種類在父類中體現,如果顧客需要在咖啡中加入調料呼叫setXXX方法,使用hasXXX去判斷是否有某中調料,但是就像圖中所示,會產生如果增加調料種類,需要去更改父類的方法,並且此方式無法將同分調料增加多份
好的,我們現在使用裝飾者來看看:
public abstract class Drink {
private int price;
private String description;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getDescription() {
return description+"--"+this.getPrice();
}
public void setDescription(String description) {
this.description = description;
}
public abstract int cost();
}
public class Coffer extends Drink{
@Override
public int cost() {
return super.getPrice();
}
}
public class Decaf extends Coffer{
public Decaf() {
super.setDescription("脫因咖啡");
super.setPrice(10);
}
}
public class Espresso extends Coffer{
public Espresso() {
super.setDescription("濃咖啡");
super.setPrice(11);
}
}
public class LongBlack extends Coffer{
public LongBlack() {
super.setDescription("熱咖啡");
super.setPrice(12);
}
}
public class ShortBlack extends Coffer{
public ShortBlack() {
super.setDescription("小杯黑咖啡");
super.setPrice(13);
}
}
從上面可以看出我們首先定義出一個抽象的Drink父類,用於設定和得到各個咖啡的描述及其價格,然後定義出一個Coffer類繼承自Drink類,重寫cost()方法,用於返回每次消費的價格,各個咖啡類需要繼承Coffer類在構造函中設定各自的描述及其價格,接下來我們看看裝飾者程式碼:
public class Decorator extends Drink{
Drink drink;
public Decorator(Drink drink) {
this.drink=drink;
}
@Override
public int cost() {
return super.getPrice()+this.drink.cost();
}
@Override
public String getDescription() {
return super.getDescription()+"&&"+this.drink.getDescription();
}
}
-
3 # 千鋒教育成都
Java是可以寫跨平臺應用軟體的面向物件的設計語言,是由SunMicrosystems公司於1995年推出的Java程式設計語言和Java平臺(即JavaSE,JavaEE,JavaME)的總稱。java技術具有卓越的通用性、高效性、平臺移植性,廣泛應用於個人PC、遊戲控制檯、科學超級計算機,同時擁有全球最大的開發者專業社群。在全球雲計算和移動網際網路的產業環境下,Java更具備了顯著優勢和廣闊前景。學習Java就要有方法。好的方法事半功倍。
Java學習路線加學習知識!
一.首先要了解Java的四個相關技術:Java程式設計語言、Javaclass檔案格式、Java應用程式設計介面、Java虛擬機器。理解它們之間的區別與聯絡。
Java程式語言:語法。
Java檔案格式:各種資料夾、檔案的字尾。
Java虛擬機器(JVM):處理*.class檔案的直譯器。
Java應用程式介面(JavaAPI)。
二.Java是分兩部分的:一個是編譯,一個是執行。
Javac負責的是編譯的部分,當執行Javac時,會啟動Java的編譯器程式。對指定副檔名的.Java檔案進行編譯。生成了jvm可以識別的位元組碼檔案。也就是class檔案,也就是Java的執行程式。
Java:負責執行的部分.會啟動jvm.載入執行時所需的類庫,並對class檔案進行執行.一個檔案要被執行,必須要有一個執行的起始點,這個起始點就是main函式.
Java三個體系
JavaSE以前稱為J2SE。它允許開發和部署在桌面、伺服器、嵌入式環境和實時環境中使用的Java應用程式。JavaSE包含了支援Java服務開發的類。
JavaEE(JavaPlatform,EnterpriseEdition)。這個版本以前稱為企業版本幫助開發,可伸縮且安全的伺服器端Java應用程式。JavaEE是在JavaSE的基礎上構建的,它提供Web服務、管理和通訊API,可以用來實現企業級的面向服務體系結構(service-orientedarchitecture,SOA)和Web2.0應用程式。
JavaME(JavaPlatform,MicroEdition)。這個版本以前稱為J2ME。JavaME為在移動裝置和嵌入式裝置上執行的應用程式提供一個健壯且靈活的環境。
JavaME包括靈活的使用者介面、健壯的安全模型、許多內建的網路協議以及對可以動態下載的連網和離線應用程式的豐富支援。基於JavaME規範的應用程式只需編寫一次,就可以用於許多裝置,而且可以利用每個裝置的本機功能。
讀完了這篇文章相信你已經對java有了一定的理解,java並不沒有看起來那麼好學習,對於零基礎的小夥伴更需要找一個專業的老師進行指導。
-
4 # java程式媛之家
1. 模式的定義
訊息分為普通訊息,加急訊息,特急訊息多種,不同的訊息型別,業務功能處理是不一樣的,現在要實現這樣傳送提示訊息的功能,該如何實現呢?
如何才能既實現功能,又能靈活地擴充套件呢?
橋接模式的定義: 將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
2. UML圖
Abstraction:抽象部分的介面,通常在這個物件中,要維護一個實現部分的物件引用,抽象物件裡面的方法,需要呼叫實現部分的物件來完成。
RefinedAbstraction:擴充套件抽象部分的介面,通常在這些物件中,定義跟實際業務相關的方法。
Implementor:定義實現部分的介面,通常由Implementor介面提供基本的操作,Abstraction中定義的是基於這些基本操作的業務方法
concreteImplementor:真正實現Implementor介面的物件
//抽象部分就是各個訊息的型別所對應的功能,而實現部分就是各種傳送訊息的方式/**
* 實現傳送訊息的統一介面
*/public interface MessageImplementor {
/**
* 傳送訊息
* @param message 要傳送的訊息內容
* @param toUser 把訊息傳送的目的人員
*/
public void send(String message,String toUser);
}/**
* 以站內短訊息的方式傳送訊息
*/public class MessageSMS implements MessageImplementor{
public void send(String message, String toUser) {
System.out.println("使用站內短訊息的方式,傳送訊息""+message+""給"+toUser);
}
}/**
* 以Email的方式傳送訊息
*/public class MessageEmail implements MessageImplementor{
public void send(String message, String toUser) {
System.out.println("使用Email的方式,傳送訊息""+message+""給"+toUser);
}
}/**
* 以手機短訊息的方式傳送訊息
*/public class MessageMobile implements MessageImplementor{
public void send(String message, String toUser) {
System.out.println("使用手機短訊息的方式,傳送訊息""+message+""給"+toUser);
}
}/**
* 抽象的訊息物件
*/public abstract class AbstractMessage {
/**
* 持有一個實現部分的物件
*/
protected MessageImplementor impl; /**
* 構造方法,傳入實現部分的物件
* @param impl 實現部分的物件
*/
public AbstractMessage(MessageImplementor impl){ this.impl = impl;
} /**
* 傳送訊息,轉調實現部分的方法
* @param message 要傳送的訊息內容
* @param toUser 把訊息傳送的目的人員
*/
public void sendMessage(String message,String toUser){ this.impl.send(message, toUser);
}
}/**
* 普通訊息
*/public class CommonMessage extends AbstractMessage{
public CommonMessage(MessageImplementor impl) { super(impl);
} public void sendMessage(String message, String toUser) { //對於普通訊息,什麼都不幹,直接呼叫父類的方法,把訊息傳送出去就可以了
super.sendMessage(message, toUser);
}
}/**
* 加急訊息
*/public class UrgencyMessage extends AbstractMessage{
public UrgencyMessage(MessageImplementor impl) { super(impl);
} public void sendMessage(String message, String toUser) {
message = "加急:"+message; super.sendMessage(message, toUser);
} /**
* 監控某訊息的處理過程
* @param messageId 被監控的訊息的編號
* @return 包含監控到的資料物件,這裡示意一下,所以用了Object
*/
public Object watch(String messageId) { //獲取相應的資料,組織成監控的資料物件,然後返回
return null;
}
}/**
* 特急訊息
*/public class SpecialUrgencyMessage extends AbstractMessage{
public SpecialUrgencyMessage(MessageImplementor impl) { super(impl);
} public void hurry(String messageId) { //執行催促的業務,發出催促的資訊
} public void sendMessage(String message, String toUser) {
message = "特急:"+message; super.sendMessage(message, toUser); //還需要增加一條待催促的資訊
}
}public class Client {
public static void main(String[] args) { //建立具體的實現物件
MessageImplementor impl = new MessageSMS(); //建立一個普通訊息物件
AbstractMessage m = new CommonMessage(impl);
m.sendMessage("請喝一杯茶", "小李"); //建立一個緊急訊息物件
m = new UrgencyMessage(impl);
m.sendMessage("請喝一杯茶", "小李"); //建立一個特急訊息物件
m = new SpecialUrgencyMessage(impl);
m.sendMessage("請喝一杯茶", "小李"); //把實現方式切換成手機短訊息,然後再實現一遍
impl = new MessageMobile();
m = new CommonMessage(impl);
m.sendMessage("請喝一杯茶", "小李");
m = new UrgencyMessage(impl);
m.sendMessage("請喝一杯茶", "小李");
m = new SpecialUrgencyMessage(impl);
m.sendMessage("請喝一杯茶", "小李");
}
}
3. 研磨設計模式
1) 什麼是橋接?為何需要橋接?如何橋接?
所謂橋接,通俗點就是在不同的東西之間搭一個橋,讓它們能夠連線起來,可以相互通訊和使用。
為被分離了的抽象部分和實現部分來搭橋,只要讓抽象部分擁有實現部分的介面物件,就橋接上了
為了達到讓抽象部分和實現部分都可以獨立變化的目的
抽象部分的實現通常是需要呼叫實現部分的功能來實現的
2) 繼承是擴充套件物件功能的一種常見手段,通常情況下,繼承擴充套件的功能變化維度都是一維的。
3)由誰來橋接: 就是誰來負責建立抽象部分和實現部分的關係,即誰來負責建立Implementor物件,並把它設定到抽象部分的物件中去。 - 由客戶端負責建立Implementor,並在建立抽象部分物件的時候,把它設定到抽象部分的物件中 - 可以抽象工廠或簡單工廠來選擇建立具體的Implementor物件,抽象部分的類可以透過工廠的方法來獲取Implementor物件 - 使用IOC/DI容器來建立具體的Implementor物件,並注入到Abstraction中
4) 典型的例子 JDBC:抽象部分是JDBC的API,具體實現式驅動程式
5)橋接模式的本質:分離抽象和實現 只有把抽象部分和實現部分分離開,才能夠讓它們獨立地變化。
回覆列表
設計模式在實際工作中的運用是一個潛移默化的過程,如果為了設計模式而設計模式,可能走上過度設計的歧途,自己也會感覺很彆扭。
要想用好設計模式,我有以下三點經驗:
1,首先徹底理解設計模式,為什麼會有這23種設計模式,都解決的什麼問題?
2,學習設計模式的使用樣例。在很多開原始碼中都會找到典型的使用設計模式的例子
3,理解自己的業務。先別急著套用設計模式。先理解自己的程式碼。看看是否有些程式碼可以最佳化。
循序漸進,不要急