Java學習 - 設計模式

設計模式

此文章部分來於網絡,爲了學習總結。java

1、原型模式(Prototype)

介紹:從一個對象再建立另外一個對象,而不需知道任何細節。面試

一、兩種表現形式數據庫

(1)簡單形式
原型模式(簡單形式)apache

(2)登記形式
原型模式(登記形式)設計模式

這兩種表現形式僅僅是原型模式的不一樣實現。安全

二、倆種克隆方法網絡

(1)淺複製ide

介紹:只克隆值傳遞的數據(好比基本數據類型、String),而不復制它所引用的對象,就是對其餘對象的引用都指向原來的對象。

注意:可實現Cloneable接口。

(2)深複製學習

介紹:除了淺度克隆要克隆的值外,還負責克隆引用類型的數據,把要複製的對象所引用的對象都複製了一遍。

注意:採用字節流寫入寫出對象,全部對象必須實現Serializable。Thread和Socket對象必須設置transient,不予複製。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Prototype implements Cloneable, Serializable{
    
    @Override
    protected Object clone() throws CloneNotSupportedException { //淺克隆
        // TODO Auto-generated method stub
        Prototype prototype = (Prototype) super.clone();
        return prototype;
    }
    
    public Object deepClone(){ //深克隆
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return ois.readObject();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            return null;
        }
    }
    
}

2、模板方法模式

介紹:將重複的部分上升到父類。ui

舉例:公司的面試題是相同的,只有應聘者的答案不一樣,因此相同的問題在父類中表現,子類只用做記錄答案。

public class TestPaper {
    
    public void testQuestion1(){
        System.out.println("1 + 1 = ");
        System.out.println("答案是:" + answer());
    }
    
    protected String answer(){
        return "";
    }

}
public class TestPaperA extends TestPaper {
    
    @Override
    protected String answer() {
        // TODO Auto-generated method stub
        return "2";
    }

}
public class Client {
    
    public static void main(String[] args) {
        TestPaper testPagerA = new TestPaperA();
        testPagerA.question();        
    }
    
}

3、外觀模式(Fade)

介紹:定義一個高層接口,使得子系統更容易使用。

外觀模式

4、建造者模式(Builder)

介紹:將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。

圖片描述

舉例:遇到多個構造器參數時考慮使用構建器,而不是重疊構造器模式或JavaBean模式調用setter方法。(靜態工廠和構造器有個共同的侷限性:它們不能很好地擴展大量的可選參數)

/**
 * 構建器模式
 * @author alex
 * @date 2017年4月6日
 */
public class A {
    
    private final int a;
    private final int b;
    private final int c;
    
    public static class A_son {
        private final int a;
        private final int b;
        private int c = 0;
        
        public A_son(int a, int b) {
            this.a = a;
            this.b = b;
        }

        public A_son c(int val) { 
            c = val;
            return this;
        }
        
        public A build() {
            return new A(this);
        }
        
    }

    public A(A_son a_son) {
        a = a_son.a;
        b = a_son.b;
        c = a_son.c;
    }
    
}
A a = new A.A_son(12, 12).c(12).build(); //客戶端調用

缺點:構建器模式可能比重疊構造器更加冗長,參數多時使用較好。若是構建器沒有在最初使用,後期使用會有些難以控制,一般一開始就使用構建器。

優勢:構建器比重疊構造器的客戶端代碼易讀寫。比JavaBean更安全。

5、觀察者模式

6、工廠方法模式

圖片描述

舉例:項目中可能須要訪問多種類型的數據庫,數據庫訪問與邏輯業務應該獨立分開,只需在客戶端建立工廠類。

7、抽象工廠模式

圖片描述

8、狀態模式

介紹:將對象轉換的邏輯判斷轉移到不一樣狀態的類中,來簡化複雜的邏輯判斷。若是邏輯判斷很簡單就不須要用此模式了。

圖片描述

abstract class State {
    
    public abstract void handle(Context context);

}

public class Context {
    
    private State state;

    public Context(State state) {
        this.state = state;
    }
    
    public void request() {
        state.handle(this);
    }

    public State getState() {
        System.out.println("當前狀態: " + state.getClass().toString());
        return state;
    }

    public void setState(State state) {
        this.state = state;
        getState();
    }
    
}

public class ConcreteStateA extends State {

    @Override
    public void handle(Context context) {
        // TODO Auto-generated method stub
        context.setState(new ConcreteStateB()); // 建立下一個邏輯判斷
    }

}
public class ConcreteStateB extends State {

    @Override
    public void handle(Context context) {
        // TODO Auto-generated method stub
        context.setState(new ConcreteStateA());
    }

}

public class Test {
    
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStateA());
        context.request();
        context.request();
        context.request();
    }

}

9、適配器模式

介紹:系統的數據和行爲都正確,但接口不符時,使得一個原有對象與某個接口匹配。

舉例:假如巴西隊中有中國球員,防止語言間的差別,中國球員須要翻譯來與團隊交流。

圖片描述

10、備忘錄模式

介紹:捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。以後可恢復以前的狀態。

public class Originator {
    
    private String state;
    
    public Memento createMemento() {
        return new Memento(state);
    }
    
    public void setMemento(Memento memento) {
        state = memento.getState();
    }
    
    public void show() {
        System.out.println("state =" + state);
    }

    public String getState() {
        return state;
    }

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

public class Caretaker {
    
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
    
}

public class Memento {
    
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

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

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Originator originator = new Originator();
        originator.setState("on");
        originator.show();
        
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(originator.createMemento());
        
        originator.setState("asdasd");
        originator.show();
        
        originator.setMemento(caretaker.getMemento());
        originator.show();
    }

}

缺點:易消耗內存。

11、組合模式

介紹:將對象組合成樹形結構來表示部分-總體,使部分與總體具備一致性。

public abstract class Component {

    protected String name;

    public Component(String name) {
        this.name = name;
    }
    
    public abstract void add(Component c);
    public abstract void remove(Component c);
    public abstract void display(int depth);
    
}

import org.apache.commons.lang.StringUtils;

public class Leaf extends Component {

    public Leaf(String name) {
        super(name);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void add(Component c) {
        // TODO Auto-generated method stub
        System.out.println("Don't add component");
    }

    @Override
    public void remove(Component c) {
        // TODO Auto-generated method stub
        System.out.println("Don't remove component");
    }

    @Override
    public void display(int depth) {
        // TODO Auto-generated method stub
        System.out.println(StringUtils.repeat("-", depth) + name);
    }

}

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

public class Composite extends Component {
    
    private List<Component> list = new ArrayList<Component>();

    public Composite(String name) {
        super(name);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void add(Component c) {
        // TODO Auto-generated method stub
        list.add(c);
    }

    @Override
    public void remove(Component c) {
        // TODO Auto-generated method stub
        list.remove(c);
    }

    @Override
    public void display(int depth) {
        // TODO Auto-generated method stub
        System.out.println(StringUtils.repeat("-", depth) + name);
        for (Component component : list) {
            component.display(depth + 2);
        }
    }

}

public class Test {
    
    public static void main(String[] args) {
        Composite root = new Composite("root");
        
        root.add(new Leaf("Leaf A"));
        root.add(new Leaf("Leaf B"));
        
        Composite comp = new Composite("Composite X");
        comp.add(new Leaf("Leaf XA"));
        comp.add(new Leaf("Leaf XB"));
        
        root.add(comp);
        
        Composite comp2 = new Composite("Composite Y");
        root .add(comp2);
        
        root.display(1);
    }

}

12、迭代器模式

介紹:提供一種方法順序訪問一個聚合對象中各個元素,而又不暴露該對象的內部表示

/**
 * 迭代器抽象
 * @author chenguyan
 * @date 2017年6月16日
 */
public abstract class Iterator {
    
    public abstract Object first();
    public abstract Object next();
    public abstract boolean isDone();
    public abstract Object currentItem();

}

/**
 * 彙集抽象
 * @author chenguyan
 * @date 2017年6月16日
 */
public abstract class Aggregate {

    public abstract Iterator createIterator();

}

/**
 * 具體彙集
 * @author chenguyan
 * @date 2017年6月16日
 */
public class ConcreteAggregate extends Aggregate {

    private List<Object> items = new ArrayList<Object>();
    
    @Override
    public Iterator createIterator() {
        // TODO Auto-generated method stub
        return new ConcreteIterator(this);
    }
    
    public int count() {
        return items.size();
    }
    
    public Object get(int index) {
        return items.get(index);
    }
    
    public void add(Object obj) {
        items.add(obj);
    }

}

/**
 * 具體迭代器
 * @author chenguyan
 * @date 2017年6月16日
 */
public class ConcreteIterator extends Iterator {
    
    private ConcreteAggregate concreteAggregate;
    private int current = 0;
    
    public ConcreteIterator(ConcreteAggregate concrete) {
        // TODO Auto-generated constructor stub
        this.concreteAggregate = concrete;
    }

    @Override
    public Object first() {
        // TODO Auto-generated method stub
        return concreteAggregate.get(0);
    }

    @Override
    public Object next() {
        // TODO Auto-generated method stub
        current++;
        if (current >= concreteAggregate.count()) {
            return null;
        }
        return concreteAggregate.get(current);
    }

    @Override
    public boolean isDone() {
        // TODO Auto-generated method stub
        return current > concreteAggregate.count() ? true : false;
    }

    @Override
    public Object currentItem() {
        // TODO Auto-generated method stub
        return concreteAggregate.get(current);
    }

}

/**
 * 客戶端
 * @author chenguyan
 * @date 2017年6月16日
 */
public class Client {
    
    public static void main(String[] args) {
        ConcreteAggregate concrete = new ConcreteAggregate();
        concrete.add("a");
        concrete.add("b");
        concrete.add("c");
        concrete.add("d");
        concrete.add("e");
        
        Iterator ite = new ConcreteIterator(concrete);
        
        System.out.println(ite.first().toString());
        
        while (!ite.isDone()) {
            Object item = ite.next();
            System.out.println(item != null ? item.toString() : "");
        }
    }

}

爲何會採用抽象類的方式來實現迭代器呢?由於能夠有不一樣的迭代順序,從前向後、從後向前等,因此隨意新增迭代器的實現類來達到迭代順序的不一樣,並且客戶端修改部分較少。

十3、單例模式

介紹:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。

/**
 * 雙重鎖定
 * @date 2017年7月3日
 */
public class Singleton {
    
    private static Singleton singleton;
    private static Object syncObj = new Object();
    
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (syncObj) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

}

十4、橋接模式

介紹:按各自的功能進行分類,使他們能夠獨立運行。

舉例:手機的品牌與軟件都會存在不兼容的狀況,這是由於手機廠商即作硬件又作軟件,沒有統一的標準。若是有一個統一的硬件廠商設計標準,手機廠商只負責軟件,這樣每一個手機廠商開發的軟件就不存在不兼容的狀況了。

圖片描述

十5、命令模式

介紹:將請求命令封裝成對象,從而使你可用不一樣的請求命令來操做對象。

圖片描述

/**
 * 命令
 * @date 2017年8月11日
 */
public abstract class Command {
    
    private Recipient recipient;

    public void setRecipient(Recipient recipient) {
        this.recipient = recipient;
    }
    
    public abstract void doing();

}

/**
 * 烤菜命令
 * @date 2017年8月11日
 */
public class RoastVegetablesCommand extends Command {

    private Recipient recipient;
    
    @Override
    public void setRecipient(Recipient recipient) {
        // TODO Auto-generated method stub
        this.recipient = recipient;
    }
    
    @Override
    public void doing() {
        // TODO Auto-generated method stub
        System.out.println("正在烤菜");
    }
    
}

/**
 * 烤肉命令
 * @date 2017年8月11日
 */
public class RoastMeatCommand extends Command {
    
    private Recipient recipient;
    
    @Override
    public void setRecipient(Recipient recipient) {
        // TODO Auto-generated method stub
        this.recipient = recipient;
    }

    @Override
    public void doing() {
        // TODO Auto-generated method stub
        System.out.println("正在執行烤肉");
    }

}

/**
 * 接收人
 * @date 2017年8月11日
 */
public class Recipient {
    
    private String name;
    private String job;
    
    public Recipient(String name, String job) {
        this.name = name;
        this.job = job;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    
}

/**
 * 服務員
 * @date 2017年8月11日
 */
public class Waiter {
    
    private List<Command> commandList = new ArrayList<Command>();
    
    public void addOrder(Command command) {
        if (!commandList.contains(command)) {
            commandList.add(command);
        }
    }
    
    public void notifyCommand() {
        for (Command command : commandList) {
            command.doing();
        }
    }

}

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        Recipient recipient = new Recipient("大廚", "大廚");
        
        Command roastMeatCommand = new RoastMeatCommand();
        Command roastVegetablesCommand = new RoastVegetablesCommand();
        
        roastMeatCommand.setRecipient(recipient);
        roastVegetablesCommand.setRecipient(recipient);
        
        Waiter waiter = new Waiter();
        waiter.addOrder(roastMeatCommand);
        waiter.addOrder(roastVegetablesCommand);
        waiter.notifyCommand();
    }

}

設計原則

1、迪米特法則

介紹:若是兩個類沒必要彼此通訊,那麼這兩個類就不該當發生直接的相互做用。強調類之間的鬆耦合。

反射機制

1、調用私有域和方法(setAccessible)

class Employee{

    private int id;
    private String name;
    private int age;
    
    public Employee(){}
    
    public Employee(int id, String name, int age){
        this.id = id;
        this.name = name;
        this.age = age;
    }

    private void setId(int id){
       this.id = id;
    }
    
    private int judge(int id){
        return this.id - id;
    }
    
    private String sayHalo(String name){
        return "Halo" + name;
    }
    
}
public class PrivateTest{

     public static void main(String[] args){
         Employee em = new Employee(1, "Alex", 22);

         Class<?> emClass =  em.getClass();
 
         Method judgeMethod = emClass.getDeclaredMethod("judge", new Class[]{Integer.TYPE}); //獲取聲明的方法
         judgeMethod.setAccessible(true); //使成員能夠訪問
 
         Method[] allMethods = emClass.getDeclaredMethods(); //獲取全部聲明的方法
         AccessibleObject.setAccessible(allMethods, true);
        
         judgeMethod.invoke(em, new Object[]{3}); //經過反射訪問
 
         //or...
         for(Method method : allMethods){
          ...
         }
     }
     
}
相關文章
相關標籤/搜索