Java設計模式-策略、委派、模板、原型模式總結
今天學習了下Java設計模式中的策略模式、委派模式、模板模式、原型模式。
做一個學習小結。
委派模式:
委派模式和代理模式其實差不多。委派模式注重的結果而代理注重的是過程,
例子
interface I {
void f();
void g();
}
class A implements I {
public void f() { System.out.println("A: doing f()"); }
public void g() { System.out.println("A: doing g()"); }
}
class B implements I {
public void f() { System.out.println("B: doing f()"); }
public void g() { System.out.println("B: doing g()"); }
}
class C implements I {
// delegation
I i = new A();
public void f() { i.f(); }
public void g() { i.g(); }
// normal attributes
public void toA() { i = new A(); }
public void toB() { i = new B(); }
}
public class Main {
public static void main(String[] args) {
C c = new C();
c.f(); // output: A: doing f()
c.g(); // output: A: doing g()
c.toB();
c.f(); // output: B: doing f()
c.g(); // output: B: doing g()
}
}
在springmvc中,dispatcherservlet用的就是委派模式。
策略模式
策略模式屬於物件的行為模式。其用意是針對一組演算法,將每一個演算法封裝到具有共同介面的獨立的類中,從而使得它們可以相互替換。策略模式使得演算法可以在不影響到客戶端的情況下發生變化。
策略模式把一個系列的演算法封裝到一個系列的具體策略類裡面,作為一個抽象策略類的子類或策略介面的實現類。簡單地說:準備一組演算法,並將每一個演算法封裝起來,使它們可以互換。(說一個更具體的比喻吧,就是好像LOL中的英雄有四個技能,這個四個技能就是四個策略!!!)
例子:
public class Context {
// 持有一個具體策略的物件
private Strategy strategy;
/**
* 建構函式,傳入一個具體策略物件
* @param strategy 具體策略物件
*/
public Context(Strategy strategy){
this.strategy = strategy;
}
/**
* 策略方法
*/
public void contextInterface(){
strategy.strategyInterface();
}
}
public interface Strategy {
/**
* 策略方法
*/
public void strategyInterface();
}
public class ConcreteStrategyA implements Strategy {
@Override
public void strategyInterface() {
// 相關的業務
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void strategyInterface() {
// 相關的業務
}
}
public class ConcreteStrategyC implements Strategy {
@Override
public void strategyInterface() {
// 相關的業務
}
}
原型模式
原型模式就是用原型例項指定建立物件的種類,並且通過拷貝這些原型建立新的物件。
Java 中 clone方法,但是這只是淺克隆,淺克隆簡單來說就是隻會克隆複製原物件的資料域,引用型別的變數不會克隆,而是指向原來的指向。深克隆連引用型別邊量都會克隆複製。
淺複製(淺克隆) :被複制物件的所有變數都含有與原來的物件相同的值,而所有的對其他物件的引用仍然指向原來的物件。換言之,淺複製僅僅複製所考慮的物件,而不復制它所引用的物件。
深複製(深克隆) :被複制物件的所有變數都含有與原來的物件相同的值,除去那些引用其他物件的變數。那些引用其他物件的變數將指向被複制過的新物件,而不再是原有的那些被引用的物件。換言之,深複製把要複製的物件所引用的物件都複製了一遍。
可以利用序列化來做深複製,所謂物件序列化就是將物件的狀態轉換成位元組流,以後可以通過這些值再生成相同狀態的物件。
原型模式例子:
package 原型模式;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class People implements Serializable,Cloneable{
private static final long serialVersionUID = 1L;
private String name;
private String sex;
private Integer age;
private WorkExperience work;
public People(String name) {
this.name = name;
work = new WorkExperience();
}
//設定個人資訊
public void setPersonalInfo(String sex,Integer age) {
this.sex = sex;
this.age = age;
}
//設定工作經歷
public void setWorkExperience(String workDate,String company) {
work.setWorkDate(workDate);
work.setCompany(company);
}
//顯示
public void display() {
System.out.println(String.format("%s %s %s", name,sex,age));
System.out.println(String.format("工作經歷:%s %s", work.getWorkDate(), work.getCompany()));
}
//淺複製
public Object clone() {
Object obj = null;
try {
obj = super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
//深複製
public Object deepClone() throws IOException,ClassNotFoundException{
//將物件寫入流中
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
//從流中讀出來
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return (oi.readObject());
}
}
package 原型模式;
import java.io.Serializable;
public class WorkExperience implements Serializable {
private static final long serialVersionUID = 1L;
private String workDate;
private String company;
public String getWorkDate() {
return workDate;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
package 原型模式;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, IOException {
People p = new People("張三");
p.setPersonalInfo("男", 20);
p.setWorkExperience("2015-2019","阿里巴巴");
//潛複製
People p2 = (People)p.clone();
p2.setWorkExperience("2019-2022", "騰訊");
p2.setPersonalInfo("男", 22);
p.display();
p2.display();
People p3 = new People("李四");
p3.setPersonalInfo("男",24);
p3.setWorkExperience("2001-2003", "位元組躍動");
People p4 = (People)p3.deepClone();
p4.setPersonalInfo("男", 24);
p4.setWorkExperience("2008-2009", "美團");
p3.display();
p4.display();
}
}
執行結果:
張三 男 20
工作經歷:2019-2022 騰訊
張三 男 22
工作經歷:2019-2022 騰訊
李四 男 24
工作經歷:2001-2003 位元組躍動
李四 男 24
工作經歷:2008-2009 美團
模板模式
定義:
定義一個操作中演算法的骨架,而將一些步驟延遲到子類中,模板方法使得子類可以不改變演算法的結構即可重定義該演算法的某些特定步驟。
通俗點的理解就是 :完成一件事情,有固定的數個步驟,但是每個步驟根據物件的不同,而實現細節不同;就可以在父類中定義一個完成該事情的總方法,按照完成事件需要的步驟去呼叫其每個步驟的實現方法。每個步驟的具體實現,由子類完成。
例子
public abstract class DodishTemplate {
/**
* 具體的整個過程
*/
protected void dodish(){
this.preparation();
this.doing();
this.carriedDishes();
}
/**
* 備料
*/
public abstract void preparation();
/**
* 做菜
*/
public abstract void doing();
/**
* 上菜
*/
public abstract void carriedDishes ();
}
/**
* 西紅柿炒蛋
* @author aries
*/
public class EggsWithTomato extends DodishTemplate{
@Override
public void preparation() {
System.out.println("洗並切西紅柿,打雞蛋。");
}
@Override
public void doing() {
System.out.println("雞蛋倒入鍋裡,然後倒入西紅柿一起炒。");
}
@Override
public void carriedDishes() {
System.out.println("將炒好的西紅寺雞蛋裝入碟子裡,端給客人吃。");
}
}
/**
* 紅燒肉
* @author aries
*
*/
public class Bouilli extends DodishTemplate{
@Override
public void preparation() {
System.out.println("切豬肉和土豆。");
}
@Override
public void doing() {
System.out.println("將切好的豬肉倒入鍋中炒一會然後倒入土豆連炒帶燉。");
}
@Override
public void carriedDishes() {
System.out.println("將做好的紅燒肉盛進碗裡端給客人吃。");
}
}
public class App {
public static void main(String[] args) {
DodishTemplate eggsWithTomato = new EggsWithTomato();
eggsWithTomato.dodish();
System.out.println("-----------------------------");
DodishTemplate bouilli = new Bouilli();
bouilli.dodish();
}
}
模板模式的優點
(1)具體細節步驟實現定義在子類中,子類定義詳細處理演算法是不會改變演算法整體結構。
(2)程式碼複用的基本技術,在資料庫設計中尤為重要。
(3)存在一種反向的控制結構,通過一個父類呼叫其子類的操作,通過子類對父類進行擴充套件增加新的行為,符合“開閉原則”。
不足
每個不同的實現都需要定義一個子類,會導致類的個數增加,系統更加龐大。