1. 程式人生 > >Java面試--設計模式

Java面試--設計模式

設計模式

單例模式【Singleton】

定義:確保全域性最多隻有一個物件

適用:構建緩慢的物件;需要統一管理的資源

優點:1.減少記憶體的佔用            2.單例模式會阻止其他物件例項化其自己的單例物件的副本,從而確保所有物件都訪問唯一例項。            3.因為類控制了例項化過程,所以類可以靈活更改例項化過程   

缺點:1.很多全域性狀態 2. 執行緒安全性問題

建立:

1.雙重鎖模式【詳解】

 將同步內容下放到if內部,提高了執行的效率,不必每次獲取物件時都進行同步,只有第一次才同步,建立了以後就沒必要了

2.作為 Java 類的靜態變數

3.使用框架提供的能力

變繼承關係為組合關係

繼承關係

1.描述 is-a 的關係

2.不要用繼承關係來實現複用,要使用設計模式來實現複用

例 將Employee 變為 Manager

程式碼:state(狀態)模式【詳解】

Role.java

package interview.designpattern.company;

public interface Role {
  void doWork();
}

Engineer.java

package interview.designpattern.company;

public class Engineer implements Role {

  @Override
  public void doWork() {
    System.out.println("Doing engineer work.");
  }

  @Override
  public String toString() {
    return "Engineer";
  }
}

Employee.java

package interview.designpattern.company;

import java.util.List;
import java.util.Objects;

public class Employee {
  public static List<Employee> allEmployees;

  private final String name;
  private final int salary;
  private Role role;

  public Employee(String name, int salary, Role role) {
    this.name = name;
    this.salary = salary;
    this.role = role;
  }

  public void doWork() {	//新增程式碼
    role.doWork();
  }

  public void getPaid(BankEndPoint bank) {
    bank.payment(name, salary);
  }

  // Package private for logic in the package to control
  // when employees are loaded.
  static void loadAllEmployees() {
    // Loads all employees from database.
  }

  @Override
  public int hashCode() {
    return Objects.hash(name, salary, role);
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    Employee other = (Employee) obj;	//新增程式碼
    return Objects.equals(this.name, other.name)
        && Objects.equals(this.salary, other.salary)
        && Objects.equals(this.role, other.role);
  }

  @Override
  public String toString() {
    return "Employee [name=" + name
        + ", salary=" + salary
        + ", role=" + role + "]";
  }

  public String getName() {
    return name;
  }

  public int getSalary() {
    return salary;
  }

  public Role getRole() {//新增程式碼
    return role;
  }

  public void setRole(Role role) {//新增程式碼
    this.role = role;
  }
}

Tester.java

package interview.designpattern.company;

import java.util.Arrays;
import java.util.LinkedList;

public class Tester {
  public static void main(String[] args) {
    Employee employee1 = new Employee("John", 10000,
        new Engineer());
    Employee employee2 = new Employee("Mary", 20000,
        new Engineer());

    LinkedList<Employee> employees = new LinkedList<>();
    employees.add(employee1);
    employees.add(employee2);

    System.out.println("Print using for each");
    for (Employee employee : employees) {
      System.out.println(employee);
    }

    System.out.println("Testing managers");
    employee2.setRole(new Manager(Arrays.asList(employee1)));
    for (Employee employee : employees) {
      System.out.println(employee);
    }

    System.out.println("Testing doWork");
    System.out.println("Employee1");
    employee1.doWork();
    System.out.println("Employee2");
    employee2.doWork();
  }
}

輸出:

 Decorator模式【詳解】

裝飾(Decorator)模式又名包裝(Wrapper)模式。裝飾模式以對客戶端透明 的方式擴充套件物件的功能,是繼承關係的一個替代方案。

    裝飾模式以對客戶透明的方式動態地給一個物件附加上更多的責任。換言之,客戶端並不會覺得物件在裝飾前和裝飾後有什麼不同。裝飾模式使用原來被裝飾的類的一個子類的例項,把客戶端的呼叫委派到被裝飾類。關鍵在於這種擴充套件是完全透明的。與生成子類相比,它更具有靈活性。

LogginRunnable 和 CodingTask 都要滿足 Runnable 介面

CodingTask  是真正做事的,LogginRunnable  是裝飾

程式碼:LoggingRunnable.java

package interview.designpattern.task;

public class LoggingRunnable implements Runnable {

  private final Runnable innerRunnable;

  public LoggingRunnable(Runnable innerRunnable) {
    this.innerRunnable = innerRunnable;
  }

  @Override
  public void run() {
    long startTime = System.currentTimeMillis();
    System.out.println("Task started at "
        + startTime);

    innerRunnable.run();

    System.out.println("Task finished. Elapsed time: "
        + (System.currentTimeMillis() - startTime));
  }
}

CodingTask.java

package interview.designpattern.task;

public class CodingTask implements Runnable {

  private final int employeeId;

  public CodingTask(int employeeId) {
    this.employeeId = employeeId;
  }

  @Override
  public void run() {
    System.out.println("Employee " + employeeId
        + " started writing code.");

    try {
      Thread.sleep(5000);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }

    System.out.println("Employee " + employeeId
        + " finished writing code.");
  }
}

TransactionalRunnable.java

package interview.designpattern.task;

public class TransactionalRunnable implements Runnable {

  private final Runnable innerRunnable;

  public TransactionalRunnable(Runnable innerRunnable) {
    this.innerRunnable = innerRunnable;
  }

  @Override
  public void run() {
    boolean shouldRollback = false;
    try {
      beginTransaction();
      innerRunnable.run();
    } catch (Exception e) {
      shouldRollback = true;
      throw e;
    } finally {
      if (shouldRollback) {
        rollback();
      } else {
        commit();
      }
    }
  }

  private void commit() {
    System.out.println("commit");
  }

  private void rollback() {
    System.out.println("rollback");
  }

  private void beginTransaction() {
    System.out.println("beginTransaction");
  }
}

Tester.java

package interview.designpattern.task;

public class Tester {

  public static void main(String[] args) {
    new LoggingRunnable(
        new TransactionalRunnable(
            new CodingTask(0))).run();
  }
}

輸出:

如何建立物件

使用 new 來建立的缺點:

1.編譯時必須決定建立那個類的物件

2.引數意義不明確

解決方法:

抽象工廠(Abstract Factory)模式【詳解】

抽象工廠模式(Abstract Factory Pattern)是一種比較常用的模式,其定義如下:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes. 即為建立一組相關或相互依賴的物件提供一個介面,而且無須指定它們的具體類。它的通用類圖如下:

1)封裝性。每個產品的實現類不是高層模組要關心的,它要關心的是介面,是抽象,它不關心物件是如何創建出來的,這都由工廠類負責的,只要知道工廠類是誰,我就能建立一個需要的物件,省時省力。

  2)產品族內的約束為非公開狀態。例如生產男女比例的問題上,猜想女媧娘娘肯定有自己的打算,那麼在抽象工廠模式中,這些約束都在工廠內裡面實現的。

缺點

        抽象工廠模式最大的缺點就是產品族擴充套件非常困難。如果我們要增加一個產品C,也就是說產品族由原來的A和B增加到3個,那麼我們首先要在抽象類AbstractCreator中增加createProductC()方法,然後兩個實現類都要修改……說到這裡,已經知道了擴充套件的弊端了……

        注意這裡是產品族擴充套件比較困難,而不是產品等級擴充套件困難。產品等級擴充套件還是非常容易的,增加一個產品等級,只要增加一個工廠類負責新增加出來的產品生產任務即可。也就是說橫向擴充套件容易,縱向擴充套件難。