常用的七種設(shè)計(jì)模式:?jiǎn)卫J健⒐S方法模式、抽象工廠模式、代理模式、裝飾器模式、觀察者模式和責(zé)任鏈模式。
設(shè)計(jì)模式分類
設(shè)計(jì)模式根據(jù)工作的目的,分為創(chuàng)建型模式、結(jié)構(gòu)型模式和行為型模式三類。
創(chuàng)建型模式:單例模式、工廠方法模式、抽象工廠模式、創(chuàng)建者模式、原型模式。
結(jié)構(gòu)型模式:適配器模式、代理模式、裝飾器模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式:策略模式、模板方法模式、觀察者模式、迭代子模式、責(zé)任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式。
軟件設(shè)計(jì)七大原則(OOP原則)
開閉原則:對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。
里氏替換原則:不要破壞繼承體系,子類重寫方法功能發(fā)生改變,不應(yīng)該影響父類方法的含義。
依賴倒置原則:要面向接口編程,不要面向?qū)崿F(xiàn)編程。
單一職責(zé)原則:控制類的粒度大小、將對(duì)象解耦、提高其內(nèi)聚性。
接口隔離原則:要為各個(gè)類建立它們需要的專用接口。
迪米特法則:一個(gè)類應(yīng)該保持對(duì)其它對(duì)象最少的了解,降低耦合度。
合成復(fù)用原則:盡量先使用組合或者聚合等關(guān)聯(lián)關(guān)系來實(shí)現(xiàn),其次才考慮使用繼承關(guān)系來實(shí)現(xiàn)。
實(shí)際上,七大原則的目的只有一個(gè):降低對(duì)象之間的耦合,增加程序的可復(fù)用性、可擴(kuò)展性和可維護(hù)性。
1、單例模式:一個(gè)類只有一個(gè)實(shí)例,且該類能自行創(chuàng)建這個(gè)實(shí)例的一種模式
? ? ? ? ①單例類只有一個(gè)實(shí)例對(duì)象
? ? ? ? ②該單例對(duì)象必須由單例類自行創(chuàng)建
? ? ? ? ③單例類對(duì)外提供一個(gè)訪問該單例的全局訪問點(diǎn)
? ? ? ?④、優(yōu)點(diǎn)
????????????????單例模式可以保證內(nèi)存里只有一個(gè)實(shí)例,減少了內(nèi)存的開銷。
????????????????可以避免對(duì)資源的多重占用。
????????????????單例模式設(shè)置全局訪問點(diǎn),可以優(yōu)化和共享資源的訪問。
????????⑤、缺點(diǎn)
????????????????單例模式一般沒有接口,擴(kuò)展困難。
????????????????單例模式的功能代碼通常寫在一個(gè)類中,如果功能設(shè)計(jì)不合理,則很容易違背單一職責(zé)原則
? ? ? ? 餓漢式單例:類一旦加載就創(chuàng)建一個(gè)單例,保證在調(diào)用getInstance方法之前單例已經(jīng)存在,這種餓漢式單例會(huì)造成空間浪費(fèi)。
public class Hungry {
private Hungry(){}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
}
????????懶漢式單例:為了避免內(nèi)存空間浪費(fèi),采用懶漢式單例,即用到該單例對(duì)象的時(shí)候再創(chuàng)建。
public class LazyMan {
private LazyMan(){};
public static LazyMan lazyMan;
public static LazyMan getInstance(){
if (lazyMan==null){
lazyMan = new LazyMan();
}
return lazyMan;
}
}
這是最簡(jiǎn)單的懶漢式,但是,存在很大問題,單線程下這段代碼沒有問題,但是在多線程下有很大問題。
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"");
}
public static LazyMan lazyMan;
public static LazyMan getInstance(){
if (lazyMan==null){
lazyMan = new LazyMan();
}
return lazyMan;
}
public static void main(String[] args) {
for(int i=0;i<10;i++){
new Thread(()->{
lazyMan.getInstance();
}).start();
}
}
}
?會(huì)發(fā)現(xiàn)結(jié)果都不一樣,因此,并發(fā)情況下,這段代碼是有問題的。我們需要進(jìn)行兩端檢測(cè),進(jìn)行“加鎖”:synchronized (Singleton.class)。
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"");
}
public static LazyMan lazyMan;
public static LazyMan getInstance(){
if (lazyMan==null){ //第一層檢查,檢查是否有引用指向?qū)ο螅卟l(fā)情況下會(huì)有多個(gè)線程同時(shí)進(jìn)入
synchronized (LazyMan.class){ //第一層鎖,保證只有一個(gè)線程進(jìn)入
//雙重檢查,防止多個(gè)線程同時(shí)進(jìn)入第一層檢查(因單例模式只允許存在一個(gè)對(duì)象,故在創(chuàng)建對(duì)象之前無引用指向?qū)ο螅芯€程均可進(jìn)入第一層檢查)
//當(dāng)某一線程獲得鎖創(chuàng)建一個(gè)LazyMan對(duì)象時(shí),即已有引用指向?qū)ο?,lazyMan不為空,從而保證只會(huì)創(chuàng)建一個(gè)對(duì)象
//假設(shè)沒有第二層檢查,那么第一個(gè)線程創(chuàng)建完對(duì)象釋放鎖后,后面進(jìn)入對(duì)象也會(huì)創(chuàng)建對(duì)象,會(huì)產(chǎn)生多個(gè)對(duì)象
if(lazyMan==null){ //第二層檢查
//synchronized關(guān)鍵字作用為禁止指令重排,保證返回Singleton對(duì)象一定在創(chuàng)建對(duì)象后
lazyMan = new LazyMan(); //這行代碼存在的問題,不能保證原子性
實(shí)際上會(huì)執(zhí)行以下內(nèi)容:
//(1)在堆上開辟空間;(2)屬性初始化;(3)引用指向?qū)ο? //假設(shè)以上三個(gè)內(nèi)容為三條單獨(dú)指令,因指令重排可能會(huì)導(dǎo)致執(zhí)行順序?yàn)?->3->2(正常為1->2->3),當(dāng)單例模式中存在普通變量需要在構(gòu)造方法中進(jìn)行初始化操作時(shí),單線程情況下,順序重排沒有影響;但在多線程情況下,假如線程1執(zhí)行l(wèi)azyMan = new LazyMan()語(yǔ)句時(shí)先1再3,由于系統(tǒng)調(diào)度線程2的原因沒來得及執(zhí)行步驟2,但此時(shí)已有引用指向?qū)ο笠簿褪莑azyMan!=null,故線程2在第一次檢查時(shí)不滿足條件直接返回lazyMan,此時(shí)lazyMan為null
//synchronized關(guān)鍵字可保證lazyMan = new LazyMan()語(yǔ)句執(zhí)行順序?yàn)?23,因其為非原子性依舊可能存在系統(tǒng)調(diào)度問題(即執(zhí)行步驟時(shí)被打斷),但能確保的是只要lazyMan!=0,就表明一定執(zhí)行了屬性初始化操作;而若在步驟3之前被打斷,此時(shí)lazyMan依舊為null,其他線程可進(jìn)入第一層檢查向下執(zhí)行創(chuàng)建對(duì)象
}
}
}
return lazyMan;
}
public static void main(String[] args) {
for(int i=0;i<10;i++){
new Thread(()->{
lazyMan.getInstance();
}).start();
}
}
}
?可以看到結(jié)果都是只有一個(gè),按理來說是沒有問題,實(shí)際上不是,上述標(biāo)注行代碼存在問題的,不是一個(gè)原子性操作。
? ? ? ? 靜態(tài)內(nèi)部類單例:是不安全,存在問題的,是不安全,存在問題的(修改過的懶漢式單例也是如此)。
public class Inner {
private Inner(){}
public static Inner getInstance(){
return InnerClass.INNER;
}
public static class InnerClass{
private static final Inner INNER = new Inner();
}
}
2、工廠方法模式:實(shí)例化對(duì)象不是用new,用工廠方法替代。將選擇實(shí)現(xiàn)類,創(chuàng)建對(duì)象統(tǒng)一管理和控制。從而將調(diào)用者跟我們的實(shí)現(xiàn)類解耦。
? ? ? ? 簡(jiǎn)單工廠模式:用來生產(chǎn)同一等級(jí)架構(gòu)中的任意產(chǎn)品(對(duì)于增加新的產(chǎn)品,需要修改已有代碼)
在簡(jiǎn)單工廠模式中,可以根據(jù)參數(shù)的不同返回不同類的實(shí)例。簡(jiǎn)單工廠模式專門定義一個(gè)類來負(fù)責(zé)創(chuàng)建其他類的實(shí)例。
接下來創(chuàng)建一個(gè)接口,兩個(gè)實(shí)現(xiàn)類,一個(gè)工廠,一個(gè)測(cè)試類
//創(chuàng)建手機(jī)接口
public interface Phone {
void name();
}
//創(chuàng)建華為實(shí)現(xiàn)類
public class HuaWei implements Phone{
@Override
public void name() {
System.out.println("華為手機(jī)");
}
}
//創(chuàng)建小米實(shí)現(xiàn)類
public class XiaoMi implements Phone{
@Override
public void name() {
System.out.println("小米手機(jī)");
}
}
//創(chuàng)建工廠
public class PhoneFactory {
public static Phone getPhone(String phone){
if(phone.equals("華為")){
return new HuaWei();
}else if(phone.equals("小米")){
return new XiaoMi();
}else {
return null;
}
}
}
//測(cè)試類
public class Consumer {
public static void main(String[] args) {
Phone p1= PhoneFactory.getPhone("華為");
Phone p2= PhoneFactory.getPhone("小米");
p1.name();
p2.name();
}
}
得到測(cè)試結(jié)果
????????華為手機(jī)
????????小米手機(jī)
我們通過創(chuàng)建一個(gè)PhoneFactory類,成功的完成工廠的創(chuàng)建。我們?cè)趧?chuàng)建對(duì)象時(shí),也就不需要直接創(chuàng)建對(duì)象,而是可以通過創(chuàng)建工廠,這樣大大的降低了代碼的耦合性。但是,靜態(tài)工廠模式是不能添加數(shù)據(jù)的。比如說,我們想添加一個(gè)“Oppo”手機(jī)類,你不直接修改PhoneFactory工廠代碼,是不能實(shí)現(xiàn)的。所以,就有了第二種的工廠方法模式。
? ? ? ? 工廠方法模式:用來生產(chǎn)同一等級(jí)架構(gòu)中的固定產(chǎn)品,一個(gè)工廠等級(jí)結(jié)構(gòu)可以負(fù)責(zé)多個(gè)不同產(chǎn)品等級(jí)結(jié)構(gòu)中的產(chǎn)品對(duì)象的創(chuàng)建 。(支持增加任意產(chǎn)品)
//創(chuàng)建手機(jī)接口
public interface Phone {
void name();
}
//創(chuàng)建華為實(shí)現(xiàn)類
public class HuaWei implements Phone{
@Override
public void name() {
System.out.println("華為手機(jī)");
}
}
//創(chuàng)建手機(jī)工廠接口
public interface PhoneFactory {
Phone getPhone();
}
//創(chuàng)建華為工廠
public class HuaWeiFactory implements PhoneFactory{
@Override
public Phone getPhone() {
return new HuaWei();
}
}
//測(cè)試類
public class Consumer {
public static void main(String[] args) {
Phone phone = new HuaWeiFactory().getPhone();
phone.name();
}
}
得到測(cè)試結(jié)果
? ? ? ? 華為手機(jī)
我們創(chuàng)建了手機(jī)工廠接口PhoneFactory,再創(chuàng)建華為工廠HuaWeiFactory實(shí)現(xiàn)工廠,這樣就可以通過HuaWeiFactory創(chuàng)建對(duì)象。增加新的具體工廠和產(chǎn)品族很方便,比如說,我們想要增加小米,只需要?jiǎng)?chuàng)建一個(gè)小米工廠XiaoMiFactory實(shí)現(xiàn)手機(jī)工廠接口PhoneFactory,合理的解決的簡(jiǎn)單工廠模式不能修改代碼的缺點(diǎn)。但是,在現(xiàn)實(shí)使用中,簡(jiǎn)單工廠模式占絕大多數(shù)。
簡(jiǎn)單工廠模式與工廠方法模式比較:
結(jié)構(gòu)的復(fù)雜度:簡(jiǎn)單工廠模式占優(yōu)。
代碼的復(fù)雜度:簡(jiǎn)單工廠模式占優(yōu)。
編程的復(fù)雜度:簡(jiǎn)單工廠模式占優(yōu)。
管理的復(fù)雜的:簡(jiǎn)單工廠模式占優(yōu)。
因此,雖然簡(jiǎn)單工廠模式不符合設(shè)計(jì)模式,但是實(shí)際使用遠(yuǎn)大于工廠方法模式。
3、抽象工廠模式:抽象工廠模式提供了一個(gè)創(chuàng)建一系列相關(guān)或者相互依賴對(duì)象的接口,無需指定它們具體的類(圍繞一個(gè)超級(jí)工廠創(chuàng)建其他工廠,該超級(jí)工廠稱為工廠的工廠)
抽象工廠模式得主要角色:
????????1、抽象工廠(Abstract Factory)提供了創(chuàng)建產(chǎn)品的接口,它包含多個(gè)創(chuàng)建產(chǎn)品的方法 newProduct(),可以創(chuàng)建多個(gè)不同等級(jí)的產(chǎn)品。
2具體工廠(Concrete Factory)主要是實(shí)現(xiàn)抽象工廠中的多個(gè)抽象方法,完成具體產(chǎn)品的創(chuàng)建。
3抽象產(chǎn)品(Product)定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能,抽象工廠模式有多個(gè)抽象產(chǎn)品。
4具體產(chǎn)品(ConcreteProduct)實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來創(chuàng)建,它同具體工廠之間是多對(duì)一的關(guān)系。
//電腦接口
public interface Computer {
void play();
void watch();
}
//創(chuàng)建華為電腦對(duì)象
public class HuaWeiComputer implements Computer{
@Override
public void play() {
System.out.println("HuaWei's play!");
}
@Override
public void watch() {
System.out.println("HuaWei's watch!");
}
}
//手機(jī)接口
public interface Phone {
void send();
void call();
}
//創(chuàng)建華為手機(jī)對(duì)象
public class HuaWeiPhone implements Phone{
@Override
public void send() {
System.out.println("HuaWei's send");
}
@Override
public void call() {
System.out.println("HuaWei's call");
}
}
//抽象工廠
public interface IProductFactory {
//生產(chǎn)手機(jī)
Phone phone();
//生產(chǎn)電腦
Computer computer();
}
//創(chuàng)建華為工廠
public class HuaWeiFactory implements IProductFactory{
@Override
public Phone phone() {
return new HuaWeiPhone();
}
@Override
public Computer computer() {
return new HuaWeiComputer();
}
}
//測(cè)試類
public class Consumer {
public static void main(String[] args) {
HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
Phone phone = huaWeiFactory.phone();
phone.call();
phone.send();
Computer computer = huaWeiFactory.computer();
computer.play();
computer.watch();
}
}
得到測(cè)試結(jié)果
????????HuaWei's call
????????HuaWei's send
????????HuaWei's play!
????????HuaWei's watch!
我們通過創(chuàng)建一個(gè)抽象工廠完成了對(duì)具體工廠的創(chuàng)建,只需要傳入?yún)?shù)就可以實(shí)例化對(duì)象。具體產(chǎn)品在應(yīng)用層的代碼隔離,無需關(guān)心創(chuàng)建的細(xì)節(jié)將一個(gè)系列的產(chǎn)品統(tǒng)一到一起創(chuàng)建。將一系列產(chǎn)品規(guī)劃到一起創(chuàng)建。但是,抽象工廠模式也存在著缺點(diǎn)。規(guī)定了所有可能被創(chuàng)建的產(chǎn)品集合,產(chǎn)品簇中擴(kuò)展新的產(chǎn)品困難,不可以增加產(chǎn)品,只能增加品牌。
4、代理模式:由于某些原因需要給某對(duì)象提供一個(gè)代理以控制對(duì)該對(duì)象的訪問。這時(shí),訪問對(duì)象不適合或者不能直接引用目標(biāo)對(duì)象,代理對(duì)象作為訪問對(duì)象和目標(biāo)對(duì)象之間的中介。
? ? ? ? 靜態(tài)代理模式:
? ? ? ? 角色分析:? ? ? ? ???
????????1、抽象角色:一般會(huì)使用接口或抽象類來解決
????????2、真實(shí)角色:被代理的角色
????????3、代理角色:代理真實(shí)角色,代理真實(shí)角色后我們會(huì)進(jìn)行一些附屬操作
????????4、訪問角色:訪問代理對(duì)象的人
//租房
public interface Rent {
void rent();
}
//房東
public class Master implements Rent{
@Override
public void rent() {
System.out.println("Master rent");
}
}
//中介
public class Proxy implements Rent{
private Master master;
public Proxy() {
}
public Proxy(Master master) {
this.master = master;
}
@Override
public void rent() {
see();
master.rent();
fare();
}
//看房
public void see(){
System.out.println("see");
}
//收費(fèi)
public void fare(){
System.out.println("fare");
}
}
//測(cè)試類
public class Consumer {
public static void main(String[] args) {
Master master = new Master();
//進(jìn)行代理
Proxy proxy = new Proxy(master);
//不需要通過對(duì)象,直接通過代理完成響應(yīng)業(yè)務(wù)
proxy.rent();
}
}
得到測(cè)試結(jié)果
????????see
????????Master rent
????????fare
可以從上述代碼看出,我們通過創(chuàng)建中介這一代理完成了租房,并且還有看房、收費(fèi)的附屬操作。我們不需要使用房東對(duì)象,通過使用代理中介就可以完成操作。?
代理模式優(yōu)點(diǎn):可以使真實(shí)角色的操作更加純粹!不用去關(guān)注一些公共的業(yè)務(wù),公共也就可以交給代理角色,實(shí)現(xiàn)了業(yè)務(wù)的分工,公共業(yè)務(wù)發(fā)生擴(kuò)展的時(shí)候,方便集中管理!
代理模式缺點(diǎn):一個(gè)真實(shí)角色就會(huì)產(chǎn)生一個(gè)代理角色;代碼量會(huì)翻倍開發(fā)效率會(huì)變低,也許,這樣無法理解到代理模式的好處。舉個(gè)例子也許能更好理解,比如說我們想要在原有固定功能上新增業(yè)務(wù),按照開閉原則我們是不能對(duì)原有代碼進(jìn)行修改的。但是我們可以通過代理模式,增加代理,在實(shí)現(xiàn)原有功能的情況下寫入新的功能,創(chuàng)建對(duì)象時(shí)也就可以使用代理,完成操作。
?動(dòng)態(tài)代理模式:雖然靜態(tài)代理模式可以很好的解決開閉原則,但是每有一個(gè)真實(shí)角色就會(huì)產(chǎn)生一個(gè)代理,代碼量翻倍過于臃腫,開發(fā)效率較低。因此,我們就使用動(dòng)態(tài)代理模式進(jìn)行設(shè)計(jì)。
//接口
public interface IUserService {
void add();
void delete();
void update();
void query();
}
//實(shí)現(xiàn)類
public class UserServiceImpl implements IUserService {
@Override
public void add() {
System.out.println("add");
}
@Override
public void delete() {
System.out.println("delete");
}
@Override
public void update() {
System.out.println("update");
}
@Override
public void query() {
System.out.println("query");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//自動(dòng)生成動(dòng)態(tài)代理類模板
public class ProxyInvocationHandler implements InvocationHandler {
//被代理接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//得到代理類
public Object getProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public void log(String s) {
System.out.println("[debug]:" + s);
}
//得到代理類
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
}
//測(cè)試類
public class Consumer {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
ProxyInvocationHandler handler = new ProxyInvocationHandler();
//設(shè)置代理對(duì)象
handler.setTarget(userService);
//生成代理類
IUserService proxy = (IUserService)handler.getProxy();
proxy.add();
proxy.query();
}
}
得到測(cè)試結(jié)果
????????[debug]:add
????????add
????????[debug]:query
????????query
通過測(cè)試我們可以順利的使用動(dòng)態(tài)代理模式完成一系列操作,當(dāng)我們想要添加附屬操作時(shí),我們只需要在模板中進(jìn)行添加。優(yōu)點(diǎn):①可以使真實(shí)角色的操作更加純粹!不用去關(guān)注一些公共的業(yè)務(wù)。②公共也就可以交給代理角色!實(shí)現(xiàn)了業(yè)務(wù)的分工。③公共業(yè)務(wù)發(fā)生擴(kuò)展的時(shí)候,方便集中管理。④一個(gè)動(dòng)態(tài)代理類代理的是一個(gè)接口,一般就是對(duì)應(yīng)的一類業(yè)務(wù)。⑤一個(gè)動(dòng)態(tài)代理類可以代理多個(gè)類,只要是實(shí)現(xiàn)了同一個(gè)接口即可!
5、裝飾者模式:動(dòng)態(tài)的將新功能附加到對(duì)象上。在對(duì)象功能的拓展方面,比繼承更有彈性。同時(shí)裝飾者模式也體現(xiàn)了開閉原則。
? ? ? ? 角色分析:
? ? ? ? 1、抽象構(gòu)件(Component)角色:定義一個(gè)抽象接口以規(guī)范準(zhǔn)備接收附加責(zé)任的對(duì)象。
? ? ? ? 2、具體構(gòu)件(ConcreteComponent)角色:實(shí)現(xiàn)抽象構(gòu)件,通過裝飾角色為其添加一些職責(zé)。
????????3、抽象裝飾(Decorator)角色:繼承抽象構(gòu)件,并包含具體構(gòu)件的實(shí)例,可以通過其子類擴(kuò)展具體構(gòu)件的功能。
????????4、具體裝飾(ConcreteDecorator)角色:實(shí)現(xiàn)抽象裝飾的相關(guān)方法,并給具體構(gòu)件對(duì)象添加附加的責(zé)任。
//定義抽象類
public abstract class Drink {
public abstract double cost();
}
//定義兩個(gè)抽象類的實(shí)現(xiàn)類
public class Juice extends Drink{
@Override
public double cost() {
System.out.println("juice: "+16);
return 16;
}
}
public class Milk extends Drink{
@Override
public double cost() {
System.out.println("milk: "+12);
return 12;
}
}
//定義裝飾抽象類
public abstract class Decorator extends Drink {
public abstract double cost();
}
//定義兩個(gè)裝飾具體實(shí)現(xiàn)類
public class Chocolate extends Decorator{
private final static double COST = 4;
private Drink drink;
public Chocolate(Drink drink) {
this.drink = drink;
}
@Override
public double cost() {
System.out.println("chocolate:"+4);
return COST+drink.cost();
}
}
public class Pudding extends Decorator{
private final static double COST = 5;
private Drink drink;
public Pudding(Drink drink) {
this.drink = drink;
}
@Override
public double cost() {
System.out.println("pudding:"+5);
return COST+drink.cost();
}
}
//測(cè)試類
public class Test {
public static void main(String[] args) {
Drink milk = new Milk();
milk = new Pudding(milk);
milk = new Chocolate(milk);
System.out.println(milk.cost());
}
}
得到測(cè)試結(jié)果
????????chocolate:4
????????pudding:5
????????milk: 12
????????21.0
?
可以看到非常簡(jiǎn)單的就能夠完成具體構(gòu)件和具體裝飾的組合。也可以看到結(jié)構(gòu)也非常簡(jiǎn)潔明,具體構(gòu)件在自己的package中,具體裝飾也在自己的package中。我們不管是想要增加具體構(gòu)件還是具體配飾,都可以在各自的package中添加。對(duì)已有的代碼不需要進(jìn)行任何操作,就算新加的有bug也不會(huì)影響原有代碼的操作。
6、觀察者模式:對(duì)象間的一種一對(duì)多依賴關(guān)系,使得每當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變時(shí),其相關(guān)依賴對(duì)象皆得到通知并被自動(dòng)更新。這種模式有時(shí)又稱作發(fā)布-訂閱模式、模型-視圖模式,它是對(duì)象行為型模式。
? ? ? ? 觀察者模式有點(diǎn):
? ? ? ? 1、降低了目標(biāo)與觀察者之間的耦合關(guān)系,兩者之間是抽象耦合關(guān)系。符合依賴倒置原則。
? ? ? ? 2、目標(biāo)與觀察者之間建立了一套觸發(fā)機(jī)制。
//定義觀察者接口
public interface Observer {
void response();
}
//具體化觀察者1
public class Observer1 implements Observer{
@Override
public void response() {
System.out.println("Observer1 action");
}
}
//具體化觀察者2
public class Observer2 implements Observer{
@Override
public void response() {
System.out.println("Observer2 action");
}
}
//抽象目標(biāo)
public abstract class Subject {
//創(chuàng)建觀察者集合
protected ArrayList<Observer> array = new ArrayList<Observer>();
//增加觀察者
public void add(Observer observer){
array.add(observer);
}
//刪除觀察者
public void remove(Observer observer){
array.remove(observer);
}
//通知觀察者方法
public abstract void notifyObserver();
}
//具體化目標(biāo)
public class Subject1 extends Subject{
@Override
public void notifyObserver() {
for (Observer observer :array){
observer.response();
}
}
}
//測(cè)試類
public class Test {
public static void main(String[] args) {
Subject subject = new Subject1();
Observer obs1 = new Observer1();
Observer obs2 = new Observer2();
subject.add(obs1);
subject.add(obs2);
subject.notifyObserver();
}
}
得到測(cè)試結(jié)果:
????????Observer1 action
????????Observer2 action
通過測(cè)試我們可以看到,我們不需要建立太多觀察者和具體目標(biāo)之間的聯(lián)系,大大降低了目標(biāo)與觀察者之間的耦合關(guān)系。并且結(jié)構(gòu)也十分簡(jiǎn)單明了,觀察者和目標(biāo)分別在各自的package包下。當(dāng)我們想要添加觀察者時(shí),只需要在觀察者包下進(jìn)行添加,實(shí)現(xiàn)Observer接口就可以了。
7、責(zé)任鏈模式:一種處理請(qǐng)求的模式,它讓多個(gè)處理器都有機(jī)會(huì)處理該詰求,直到其中某個(gè)處理成功為止。責(zé)任鏈模式把多個(gè)處理器串成鏈,然后讓請(qǐng)求在鏈上傳遞。
????????責(zé)任鏈模式的主要角色
????????抽象處理者(Handler)角色:定義一個(gè)處理請(qǐng)求的接口,包含抽象處理方法和一個(gè)后繼連接。
????????具體處理者(Concrete Handler)角色:實(shí)現(xiàn)抽象處理者的處理方法,判斷能否處理本次請(qǐng)求,如果可以處理請(qǐng)求則處理,否則將該請(qǐng)求轉(zhuǎn)給它的后繼者。
????????客戶類(Client)角色:創(chuàng)建處理鏈,并向鏈頭的具體處理者對(duì)象提交請(qǐng)求,它不關(guān)心處理細(xì)節(jié)和請(qǐng)求的傳遞過程。
????????責(zé)任鏈模式優(yōu)點(diǎn)
????????????????降低了對(duì)象之間的耦合度。處理者不需要知道客戶的任何信息,客戶也不要知道處理者是如何實(shí)現(xiàn)方法的。
????????????????提高了系統(tǒng)的靈活性。當(dāng)我們想要新增處理器到整個(gè)鏈條中時(shí),所付出的代價(jià)是非常小的
????????責(zé)任鏈模式缺點(diǎn)
????????????????降低了系統(tǒng)的性能。對(duì)比較長(zhǎng)的職責(zé)鏈,請(qǐng)求的處理可能涉及多個(gè)處理對(duì)象
????????????????不能保證每個(gè)請(qǐng)求一定被處理。由于一個(gè)請(qǐng)求沒有明確的接收者,所以不能保證它一定會(huì)被處理,該請(qǐng)求可能一直傳到鏈的末端都得不到處理。
//抽象處理者
public abstract class Handler {
private Handler next;
public void setNext(Handler next) { this.next = next; }
public Handler getNext() { return next; }
//處理請(qǐng)求
public abstract void handleRequest(int info);
}
//具體處理者1
public class Handler1 extends Handler{
@Override
public void handleRequest(int info) {
if (info <10){
System.out.println("Handler1完成處理");
}else {
if (getNext()!=null){
getNext().handleRequest(info);
}else {
System.out.println("沒有處理者進(jìn)行處理");
}
}
}
}
//具體處理者2
public class Handler2 extends Handler{
@Override
public void handleRequest(int info) {
if (info <20&&info>10){
System.out.println("Handler2完成處理");
}else {
if (getNext()!=null){
getNext().handleRequest(info);
}else {
System.out.println("沒有處理者進(jìn)行處理");
}
}
}
}
測(cè)試類
public class Test {
public static void main(String[] args) {
Handler handler1 = new Handler1();
Handler handler2 = new Handler2();
handler1.setNext(handler2);
handler1.handleRequest(5);
handler1.handleRequest(15);
handler1.handleRequest(25);
}
}
得到測(cè)試結(jié)果:
Handler1完成處理
Handler2完成處理
沒有處理者進(jìn)行處理文章來源:http://www.zghlxwxcb.cn/news/detail-789305.html
通過測(cè)試結(jié)果我們看到,5交給了Handler1處理,15交給了Handler2處理,而25則沒有處理者處理。請(qǐng)求者根本不需要參與處理,只需要提交數(shù)據(jù)就可以完成功能的處理,完全不需要管是哪個(gè)處理者進(jìn)行處理的。當(dāng)我們想要繼續(xù)添加處理者時(shí),這只需要再次添加就可以了,也不會(huì)對(duì)之前的代碼造成影響。文章來源地址http://www.zghlxwxcb.cn/news/detail-789305.html
到了這里,關(guān)于七種常用的設(shè)計(jì)模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!