Java 十一種設計模式深入理解

                                  `話不多說直奔主題。`
action.png

目錄
一、工廠設計模式
二、抽象工廠模式
三、單例設計模式
四、建造者(Builder)模式
五、原型模式
六、適配器設計模式
七、橋接(Bridge)設計模式
八、責任鏈模式
九、迭代器設計模式
十、觀察者模式
十一、策略設計模式


一、工廠設計模式

在工廠設計模式中,我們沒有把創(chuàng)建對象暴露給客戶端,而是通過接口的形式創(chuàng)建引入新的對象。接下來我將創(chuàng)建一個Product接口,寫ABC三種產(chǎn)品類 實現(xiàn)接口,它們將會把信息傳遞給ProductFactory,通過ProductFactory來根據(jù)情況獲取產(chǎn)品。

  • 1.1 創(chuàng)建一個接口
    Product.java
public interface Product {
    void product();
}
  • 1.2 創(chuàng)建ABC三種產(chǎn)品類 只寫一個A,BC同理。實現(xiàn)Product接口
    ProductImplA.java
public class ProductImplA implements Product {
    @Override
    public void product() {
        System.out.println("this is ProductImplA");
    }
}
  • 1.3 創(chuàng)建工廠類
    ProductFactory.java 根據(jù)工廠指定的類型,生成對象。
public class ProductFactory {
    public Product getProduct(String productType) {
        if (TextUtils.isEmpty(productType)) {
            return null;
        }
        if ("A".equals(productType)) {
            return new ProductImplA();
        } else if ("B".equals(productType)) {
            return new ProductImplB();
        } else if ("C".equals(productType)) {
            return new ProductImplC();
        }
        return null;
    }
}
  • 1.4 使用工廠,通過傳遞的信息獲取具體類的信息
private void FactoryDemo() {
        ProductFactory productFactory = new ProductFactory();
        productFactory.getProduct("A").product();
        productFactory.getProduct("B").product();
        productFactory.getProduct("C").product();
    }

-1.5 驗證信息

I/System.out: this is ProductImplA
I/System.out: this is ProductImplB
I/System.out: this is ProductImplC

二、抽象工廠模式

抽象工廠是一個大廠,用來創(chuàng)建其他工廠,可以理解為工廠的工廠。

接下來我將創(chuàng)建兩個小廠子Product與Color,與(一)工廠設計模式一樣,接口并實現(xiàn)ABC。之后創(chuàng)建一個抽象工廠類AbstractFactory,將ProductFactory和ColorFactory定義成自擴展的AbstractFactory,之后在創(chuàng)建 工廠創(chuàng)建者FactoryProducer。

  • 2.1 照著(一)工廠設計模式寫個Color,Product工廠直接拿來用。
    創(chuàng)建一個接口Color.java
public interface Color {
    void color();
}
  • 2.2 創(chuàng)建ABC三種產(chǎn)品顏色,只寫個A,BC同理 實現(xiàn)Color接口
    ColorImplA.java
public class ColorImplA implements Color {
    @Override
    public void color() {
        System.out.println("class ColorImplA , method color");
    }
}
  • 2.3 創(chuàng)建抽象工廠
    AbstractFactory.java
public abstract class AbstractFactory {
    public abstract Color getColor(String colorType);
    public abstract Product getProduct(String productType);
}

-2.4 創(chuàng)建ColorFactory工廠 注意繼承類,Product同理,但需要注意抽象方法
ColorFactory.java

public class ProductFactory extends AbstractFactory {
    @Override
    public Color getColor(String colorType) {
        return null;
    }

    @Override
    public Product getProduct(String productType) {
        if (TextUtils.isEmpty(productType)) {
            return null;
        }
        if ("productA".equals(productType)) {
            return new ProductImplA();
        } else if ("productB".equals(productType)) {
            return new ProductImplB();
        } else if ("productC".equals(productType)) {
            return new ProductImplC();
        }
        return null;
    }
}

-2.5 創(chuàng)建 創(chuàng)建工廠者, 根據(jù)傳遞信息獲取具體工廠
FactoryProducer.java

public class FactoryProducer {

    public static AbstractFactory getType(String choice) {
        if ("color".equals(choice)) {
            return new ColorFactory();
        } else if ("product".equals(choice)) {
            return new ProductFactory();
        }
        return null;
    }
}
  • 2.6 使用
private void AbstractFactory() {
        AbstractFactory colorProducer = FactoryProducer.getType("color");
        colorProducer.getColor("colorA").color();
        colorProducer.getColor("colorB").color();
        colorProducer.getColor("colorC").color();

        AbstractFactory productProducer = FactoryProducer.getType("product");
        productProducer.getProduct("productA").product();
        productProducer.getProduct("productB").product();
        productProducer.getProduct("productC").product();
    }
  • 2.7驗證信息
I/System.out: class ColorImplA , method color
I/System.out: class ColorImplB , method color
I/System.out: class ColorImplC , method color
I/System.out: class ProductImplA , method product
I/System.out: class ProductImplB , method product
I/System.out: class ProductImplC , method product

三、單例設計模式

Java中最簡單的設計模式之一,這種模式只涉及一個類,它負責創(chuàng)建一個對象,同時保證只有一個對象,這個類提供一種方法來訪問它的唯一對象,可以直接訪問而不需要實例化對象,實例化對象也只有一次。

  • 3.1 餓漢式單例
public class SingleClass {

    private static SingleClass singleClass = new SingleClass();

    public static SingleClass getInstance() {
        return singleClass;
    }
}
  • 3.2懶漢式單例
public class SingleClass {
    private static SingleClass singleClass;

    public static SingleClass getInstance() {
        if (null == singleClass) {
            singleClass = new SingleClass();
        }
        return singleClass;
    }
}

四、建造者(Builder)模式

  • 建造者模式的UML直觀圖


    image.png

    核心思想:將復雜對象的構造與表現(xiàn)分離,使同樣的構造可以產(chǎn)生不同的表現(xiàn)。

  • 4.1 創(chuàng)建核心抽象類 , 主要就是說把小步驟給抽象出來,通過調用方法來確定都生成什么表現(xiàn)。
    AbstractBuilder.java
public abstract class AbstractBuilder {

    abstract void InstallStudio();

    abstract void DownLoadSDK();

    abstract void BuildProject();

    public abstract Project getProject();
}
  • 4.2 創(chuàng)建Project類, 在這里寫數(shù)據(jù)邏輯
    Project.java
public class Project {

    private List<String> step = new ArrayList<>();

    public void add(String info) {
        step.add(info);
    }

    public void show() {
        for (int i = 0; i < step.size(); i++) {
            Log.e("step" + (i + 1), "show: " + step.get(i));
        }
        Log.e("step", "show: 安裝完成!??!");
    }

}
  • 4.3 為了更直觀表達建造者模式,我把業(yè)務層寫到了一起。
    Controller.java
public class Controller extends AbstractBuilder {

    private Project project;

    public Controller() {
        project = new Project();
    }

    @Override
    void InstallStudio() {
        project.add("安裝Studio");
    }

    @Override
    void DownLoadSDK() {
        project.add("下載SDK");
    }

    @Override
    void BuildProject() {
        project.add("build項目");
    }


    @Override
    public Project getProject() {
        return project;
    }

    public static class Builder {

        private AbstractBuilder abstractBuilder;

        public Builder(AbstractBuilder abstractBuilder) {
            this.abstractBuilder = abstractBuilder;
        }

        public Builder create() {
            abstractBuilder.InstallStudio();
            abstractBuilder.DownLoadSDK();
            abstractBuilder.BuildProject();
            return this;
        }


        public Builder getProject() {
            abstractBuilder.getProject();
            return this;
        }

        public Builder show() {
            abstractBuilder.getProject().show();
            return this;
        }
    }
}
  • 4.4 調用
Controller.Builder builder = new Controller.Builder(new Controller());
        builder.create().getProject().show();
  • 4.5 驗證信息
step1: show: 安裝Studio
step2: show: 下載SDK
step3: show: build項目
step: show: 編譯完成?。。?

五、原型模式

核心思想:復制粘貼都用過,復制的文件跟原文件沒有一點差別。
概念:用原型實例 指定創(chuàng)建對象的種類,并通過拷貝這些原型創(chuàng)建新的對象。

  • 5.1 淺拷貝
    只拷貝對象中的基本數(shù)據(jù)類型(8種),對于數(shù)組、容器、引用對象等都不會拷貝
  • 5.1.1淺拷貝的代碼實現(xiàn) 創(chuàng)建附件類
    AttachType.java
public class AttachType {
    **get,set,tostring方法隱藏,但實際有
    private String attach;
}
  • 5.1.2 定義抽象原型
    Student.java
public class Student implements Cloneable {
    **get,set,tostring方法隱藏,但實際有
    private AttachType attachType;
    private String name;
  
    public Student clone() {
        Student student = null;
        try {
            student = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return student;
    }
}

  • 5.1.3 模擬實現(xiàn)
private void catalog() {
        Student student1 = new Student();
        AttachType attachType = new AttachType("aaa");
        student1.setName("張三");
        student1.setAttachType(attachType);

        Student student2 = student1.clone();
        student2.setName("李四");
        student2.getAttachType().setAttach("bbb");

        System.out.println(">>>s1" + student1.toString());
        System.out.println(">>>s2" + student2.toString());
    }

-5.1.4 輸出結果

I/System.out: >>>s1Student{attachType=AttachType{attach='bbb'}, name='張三'}
I/System.out: >>>s2Student{attachType=AttachType{attach='bbb'}, name='李四'}

可以看到只改動了name,AttachType對象,并沒有分離出來。

  • 5.2深克隆
    拷貝對象中的基本數(shù)據(jù)類型(8種),對于數(shù)組、容器、引用對象等都會拷貝。
    深克隆需要注意的是,所有的類,都要實現(xiàn)Cloneable,并且在宿主bean做處理。
  • 5.2.1創(chuàng)建附件類
    AttachType_2.java
public class AttachType_2 implements Cloneable {
    ** get,set,tostring方法隱藏,但實際有
    private String attach;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

-5.2.2定義抽象原型
Student_2.java

public class Student_2 implements Cloneable {
    ** get,set,tostring方法隱藏,但實際有
    private AttachType attachType;
    private String name;

    public Student_2 clone() {
        Student_2 student_2 = null;
        try {
            student_2 = (Student_2) super.clone();
            student_2.setAttachType((AttachType) student_2.getAttachType().clone());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return (Student_2) student_2;
    }
}
  • 5.3調用同步5.1.2
  • 5.4驗證結果
I/System.out: >>>s1Student{attachType=AttachType{attach='aaa'}, name='張三'}
I/System.out: >>>s2Student{attachType=AttachType{attach='bbb'}, name='李四'}

處理之后,AttachType_2也被拷貝了。
在某種情況下,合理使用可節(jié)省避免不必要的開支。


六、適配器設計模式

概念:負責連接獨立或不兼容的接口。
可分為對象適配和類適配模式。
三個角色,目標接口或類、適配類或接口、適配器

  • 對象適配
  • 6.1 簡單目標類
    目標類處理將語言都轉換成英文,屬于獨立的類。
    ConvertEnglish.java
public class ConvertEnglish {

    void convertToEnglish(String info) {
        System.out.println(">>>轉換成英文 : " + info);
    }
}
  • 6.1.2 簡單適配接口
    需要將我說的漢語都轉換成英語
public interface SpeakChinese {
    void speakChinese(String chinese);
}
  • 6.1.3 適配器
    將功能委托給目標來完成實現(xiàn)。
public class TransformationAdapter implements SpeakChinese {

    private ConvertEnglish convertEnglish;

    public TransformationAdapter(ConvertEnglish convertEnglish) {
        this.convertEnglish = convertEnglish;
    }

    @Override
    public void speakChinese(String chinese) {
        convertEnglish.convertToEnglish(chinese);
    }
}
  • 6.1.4 使用
TransformationAdapter adapter = new TransformationAdapter(new ConvertEnglish());
        adapter.speakChinese("我需要轉換成英文");

I/System.out: >>>轉換成英文 : 我需要轉換成英文

對象適配器可以傳入多個不同的對象,用來幫忙處理。

  • 類適配
  • 6.2.1 還是剛才的類,只需要改動適配器即可
public class TransformationAdapter extends ConvertEnglish implements SpeakChinese {
    @Override
    public void speakChinese(String chinese) {
        super.convertToEnglish(chinese);
    }
}

可以看到是通過extends的方式來獲取目標類的屬性,但是java中不支持多繼承,所以在使用類適配的時候,每一個目標類需要單獨寫一個。


七、橋接模式

概念:使得具體實現(xiàn)類和接口實現(xiàn)類獨立。

  • 7.1 需要一個接口
    Animation.java
public interface Animation {
    void onDraw(int radius, int x, int y);
}
  • 7.2聲明兩個接口實現(xiàn)類
    RotateImpl.java 和 TranslationImpl.java
public class RotateImpl implements Animation {
    @Override
    public void onDraw(int radius, int x, int y) {
        System.out.println(">>>DrawingRotate:" + radius + "," + x + "," + y);
    }
}

public class TranslationImpl implements Animation {
    @Override
    public void onDraw(int radius, int x, int y) {
        System.out.println(">>>DrawingTranslation:" + radius + "," + x + "," + y);
    }
}
  • 7.3 橋梁抽象類
    AbstractShape.java
public abstract class AbstractShape {

    protected Animation animation;

    public AbstractShape(Animation animation) {
        this.animation = animation;
    }

    abstract void onDraw();
}
  • 7.4 橋梁具體實現(xiàn)類
    ShapeImpl.java
public class ShapeImpl extends AbstractShape {

    private int radius, x, y;

    public ShapeImpl(int radius, int x, int y, Animation animation) {
        super(animation);
        this.radius = radius;
        this.x = x;
        this.y = y;
    }

    @Override
    public void onDraw() {
        animation.onDraw(radius, x, y);
    }
}
  • 7.5使用
ShapeImpl rotate = new ShapeImpl(9, 100, 100, new RotateImpl());
ShapeImpl translate = new ShapeImpl(15, 200, 300, new TranslationImpl());
rotate.onDraw();
translate.onDraw();

···
log
>>>DrawingRotate:9,100,100
>>>DrawingTranslation:15,200,300

使得具體實現(xiàn)類與接口實現(xiàn)類解耦,兩種類都可以在結構上發(fā)生改變并且互不影響。


八、責任鏈模式

概念:將同一請求形成一條鏈,由鏈進行傳遞,能處理的處理,處理不了的繼續(xù)傳遞。

  • 8.1 寫個請求bean,用來處理同一類請求
    RequestBean.java
public class RequestBean {
   ** 省略了get set
    //小于18歲   大約18歲小于30歲  大于30歲小于60歲的
    private String name;
    private int age;
    private String remark;
{
  • 8.2責任鏈抽象類
    AbstractHandler.java
public abstract class AbstractHandler {

    protected String handlerName;//當前處理的是誰
    protected AbstractHandler nextMessage;//捆綁

    public AbstractHandler(String handlerName) {
        this.handlerName = handlerName;
    }

    public void setNextMessage(AbstractHandler nextMessage) {
        this.nextMessage = nextMessage;
    }

    public abstract void handlerRequest(RequestBean requestBean);//子類核心處理方法

}
  • 8.3 員工ABC 三條處理
    StaffA.java
public class StaffA extends AbstractHandler {

    public StaffA(String handlerName) {
        super(handlerName);
    }

    @Override
    public void handlerRequest(RequestBean requestBean) {
        if (requestBean.getAge() < 18) {
            System.out.println(">>>由" + this.handlerName + "處理了:" + requestBean.getAge() + "," + requestBean
                    .getName() + "," + requestBean.getRemark());
        } else {
            if (this.nextMessage != null) {
                this.nextMessage.handlerRequest(requestBean);
            }
        }
    }
}

-8.4 員工B
StaffB.java

public class StaffB extends AbstractHandler {

    public StaffB(String handlerName) {
        super(handlerName);
    }

    @Override
    public void handlerRequest(RequestBean requestBean) {
        if (18 < requestBean.getAge() && requestBean.getAge() < 30) {
            System.out.println(">>>由" + this.handlerName + "處理了:" + requestBean.getAge() + "," + requestBean
                    .getName() + "," + requestBean.getRemark());
        } else {
            if (this.nextMessage != null) {
                this.nextMessage.handlerRequest(requestBean);
            }
        }
    }
}

員工C同理,此處不寫了。

  • 8.5 責任關聯(lián)
private void startChain() {
        AbstractHandler a = new StaffA("張三");
        AbstractHandler b = new StaffB("李四");
        AbstractHandler c = new StaffC("王五");
        
        a.setNextMessage(b);
        b.setNextMessage(c);
        
        RequestBean request = new RequestBean();
        request.setAge(25);
        request.setName("趙二");
        request.setRemark("無");
        a.handlerRequest(request);
    }
  • 8.6 驗證結果
I/System.out: >>>由李四處理了:25,趙二,無

九、迭代器設計模式

概念:不需要暴露內(nèi)部結構的同時,可以讓外部遍歷數(shù)據(jù)。

  • 9.1 構建迭代接口
    MyIterator.java 和 Container.java
    因為是遍歷我肯定需要知道還有沒有下一條數(shù)據(jù)。
public interface MyIterator {
    boolean hasNext();//判定是否有下一條

    Object next();
}

public interface Container {
    MyIterator getMyIterator();
}
  • 9.2迭代類
public class ContainerImpl implements Container {

    private String[] strings = new String[]{"aa", "bb", "cc", "dd", "ee"};

    @Override
    public MyIterator getMyIterator() {
        return new Iterator();
    }

    class Iterator implements MyIterator {

        private int index;

        @Override
        public boolean hasNext() {
            if (index < strings.length) {
                return true;
            }
            return false;
        }

        @Override
        public Object next() {
            if (this.hasNext()) {
                return strings[index++];
            }
            return null;
        }
    }
}

hasNext處理我是否還有下一條數(shù)據(jù),在有的前提下我才可以在next方法中return出去,至于為啥要++,next方法肯定在循環(huán)中唄。

  • 9.3使用
ContainerImpl container = new ContainerImpl();
for (MyIterator myIterator = container.getMyIterator(); myIterator.hasNext(); ) {
            String next = (String) myIterator.next();
            System.out.println(">>>next" + next);
}
  • 9.4驗證信息
I/System.out: >>>nextaa
I/System.out: >>>nextbb
I/System.out: >>>nextcc
I/System.out: >>>nextdd
I/System.out: >>>nextee

十、觀察者模式

概念:如果一個對象被修改,它的依賴對象將會被自動通知。
自動通知其實就是在 合理的時間調用通知接口,直接上代碼。

  • 10.1 抽象類
    MyObserver.java
    依賴對象會被自動通知?所以 抽象肯定有一個依賴類,一個通知接口
public abstract class MyObserver {

    protected Subscriber subscriber;

    abstract void update();

}
  • 10.2 依賴類
public class Subscriber {

    private MyObserver myObserver;

    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        notifyAllObserver();
    }

    //綁定
    public void attach(MyObserver myObserver) {
        this.myObserver = myObserver;
    }

    //通知
    public void notifyAllObserver() {
        myObserver.update();
    }
}

可以看到,引入MyObserver抽象類,通過調用MyObserver.update來做通知,所以合理的地方調用notifyAllObserver很重要。

  • 10.3 抽象具體類
    ObserverImpl.java
public class ObserverImpl extends MyObserver {

    public ObserverImpl(Subscriber subscriber) {
        this.subscriber = subscriber;
        this.subscriber.attach(this);
    }

    @Override
    public void update() {
        System.out.println(">>>this update now");
    }
}
  • 10.4 使用
private Subscriber subscriber;//成員變量,點擊的時候做通知

subscriber = new Subscriber();
        new ObserverImpl(subscriber);

btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                subscriber.setState(1);
            }
        });

subscriber 寫成了成員變量,在click view的時候,做了setState值更新。更新就是通知該 調用update接口了。
-10.5 驗證信息

 I/System.out: >>>this update now

十一、策略設計模式

概念:針對一組算法,將每一種算法都封裝到具有共同接口的獨立的類中,從而是它們可以相互替換。策略模式的最大特點是使得算法可以在不影響客戶端的情況下發(fā)生變化,從而改變不同的功能。

  • 11.1 定義共有接口類
    IStrategy.java
    共有接口類,計算不同的a,b參數(shù)處理方式
public interface IStrategy {
    void strategyType(int a, int b);
}
  • 11.2 共有接口類ab計算,策略之一
    StrategyA.java 加法
public class StrategyA implements IStrategy {

    @Override
    public void strategyType(int a, int b) {
        //處理算法。
        int sum = a + b;
        System.out.println(">>>sum" + sum);
    }
}
  • 11.3共有接口類ab計算,策略之一
    StrategyB.java 乘法
public class StrategyB implements IStrategy {

    @Override
    public void strategyType(int a, int b) {
        //處理算法。
        int sum = a * b;
        System.out.println(">>>sum" + sum);
    }
}

還寫了個減法,同步上面都一樣。主要是為了表現(xiàn)策略之一。

  • 11.4 策略調用類
    StrategyImpl.java
public class StrategyImpl {

    private IStrategy iStrategy;

    public StrategyImpl(IStrategy iStrategy) {
        this.iStrategy = iStrategy;
    }

    public void strategyType(int a, int b) {
        iStrategy.strategyType(a, b);
    }

}
  • 11.5使用
private void strategy() {
        int a = 10;
        int b = 5;
        StrategyImpl strategy = new StrategyImpl(new StrategyA());
        strategy.strategyType(a, b);

        StrategyImpl strategy2 = new StrategyImpl(new StrategyB());
        strategy2.strategyType(a, b);

        StrategyImpl strategy3 = new StrategyImpl(new StrategyC());
        strategy3.strategyType(a, b);
    }
  • 11.6驗證信息
 I/System.out: >>>sum15
 I/System.out: >>>sum50
 I/System.out: >>>sum5

策略模式的好處是 實現(xiàn)可以自由切換,擴展性也比較好,閱讀代碼很直觀。

結語
設計模式 真的是可以規(guī)范代碼,并且提高對源碼的理解。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容