前言
憋在家裡的第8天,今天開始進入結構型設計模式。
思維導圖
結構型設計模式是從程式的結構上解決模組之間的耦合問題。
代理模式
定義:為其他物件提供一種代理以控制對這個物件的訪問。
這個模式的幾個角色分為以下:
- Subject:抽象主題類。
- RealSubject:真實主題類,客戶端由Proxy來間接呼叫。
- Proxy:代理類
這個模式就像你和代購的存在一樣,你提出需求,由代購來幫你購買。這個句子裡基本上就概括了整個代理模式的全貌。客戶端就是我們需求者,而真實主題就是你要找的代購幫你買,最後一個代理,找誰買。 以下用程式碼表示靜態代理。
/**
* 抽象主題類
* 中心主題,買東西。
*/
public interface Shop {
void buy();
}
/**
* 真實主題類
* 有這麼一個人,可以幹這件事,他就是代理
*/
public class Person implements Shop {
@Override
public void buy() {
System.out.println("購買");
}
}
/**
* 代理類
* 你要告訴自己找那個代購買
*/
public class WhoBuy implements Shop {
private Shop shop;
WhoBuy(Shop shop){
this.shop = shop;
}
@Override
public void buy() {
shop.buy();
}
}
/**
* 客戶端類
* 就是這個想買東西的人了
*/
public class User {
public static void main(String[] args) {
Shop person = new Person();
Shop purchase = new WhoBuy(person);
purchase.buy();
}
}
複製程式碼
靜態代理,主要是為了讓人更好的理解代理模式。在開發中主要還是使用反射機制來完成的,也就是動態代理模式。
/**
* 動態代理類
*/
public class DynamicPurchase implements InvocationHandler {
private Object object;
DynamicPurchase(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(object, args);
if(method.getName().equals("buy")){
System.out.println("買上");
}
return result;
}
}
/**
* 客戶端類
*/
public class User {
public static void main(String[] args) {
Shop person = new Person();
DynamicPurchase dynamicPurchase = new DynamicPurchase(person);
ClassLoader loader = person.getClass().getClassLoader();
Shop purchase = (Shop) Proxy.newProxyInstance(loader, new Class[]{Shop.class}, dynamicPurchase);
purchase.buy();
}
}
複製程式碼
和靜態代理的不同就在於代理類,使用反射機制。 這種代理模式的優點:
- 真實主題類只關注本身的業務邏輯。
- 真實主題類和代理類實現了公共介面,不必擔心主題類的修改影響代理類。
裝飾模式
動態地給一個物件新增一些額外的職責。
這個模式的角色有:
- Component:抽象元件。
- ConcreteComponent:元件具體實現類。
- Decorator:抽象裝飾者,用於增加Component類的功能。
- ConcreteDecorator:裝飾者的具體實現
人是一個慢慢學習的生物,從一開始只會咿咿呀呀,經過學習,學會了數學,英語。這個時候數學、英語,兩個科目就是一種裝飾了。
/**
* 抽象元件
* 作為一個人,必然會有學習的能力。
*/
public abstract class Person {
public abstract void learn();
}
/**
* 元件具體實現類
* 人一開始只會咿咿呀呀
*/
public class Me extends Person {
@Override
public void learn() {
System.out.println("咿咿呀呀");
}
}
/**
* 抽象裝飾類
* 有一個老師教書育人
*/
public abstract class Teacher extends Person {
private Person person;
Teacher(Person person){
this.person = person;
}
@Override
public void learn() {
person.learn();
}
}
/**
* 裝飾具體類
* 這個老師教數學,也就教會了孩子
*/
public class MathTeacher extends Teacher {
MathTeacher(Person person) {
super(person);
}
public void teach(){
System.out.println("學會了數學");
}
@Override
public void learn() {
super.learn();
teach();
}
}
// 具體使用
public class Main {
public static void main(String[] args) {
Person person = new Me();
MathTeacher mathTeacher = new MathTeacher(person);
mathTeacher.learn();
}
}
複製程式碼
優點:
- 能夠動態的為物件增加功能。
- 裝飾類和元件類互不干擾。 缺點:
- 不論是裝飾類,還是元件類都繼承自
Component
,如果Component
發生了改變,子類必然收到巨大的衝擊。 - 裝飾層數不宜過多,不僅影響效率,排查也比較苦難。
外觀模式
要求一個子系統 的外部與內部的通訊必須通過一個統一的物件進行。
這個模式的角色有:
- Facade:外觀類
- Subsystem:子系統類
這裡覺得之前看到的武俠的例子非常好。 一個武俠本身分為招式、內功、經脈三個系統,每次放招都是根據三個子系統的合理使用來釋放。
/**
* 三大子系統
*/
public class 經脈 {
public void jingmai(){
System.out.println("開啟經脈");
}
}
public class 內功 {
public void JiuYang(){
System.out.println("使用九陽神功");
}
public void QianKun(){
System.out.println("使用乾坤大挪移");
}
}
public class 招式 {
public void QiShangQuan(){
System.out.println("使用七傷拳");
}
public void ShengHuoLing(){
System.out.println("使用聖火令");
}
}
/**
* 外觀類
* 也就是張無忌
*/
public class 張無忌 {
private JingMai jingMai;
private NeiGong neiGong;
private ZhaoShi zhaoShi;
張無忌(){
jingMai = new JingMai();
neiGong = new NeiGong();
zhaoShi = new ZhaoShi();
}
public void QianKun(){
jingMai.jingmai();
neiGong.QianKun();
}
public void QiShang(){
jingMai.jingmai();
neiGong.JiuYang();
zhaoShi.QiShangQuan();
}
}
複製程式碼
給外人看到的只有張無忌的出招是七傷拳,但是不知道內部的具體操作,這也就是外觀類的整體展現方式了。 優點:
- 所有的依賴都是出現在外觀類的,子系統間互不干擾。
- 具體實現對使用者隱藏,也就是使用者和子系統處於鬆耦合狀態,同時保障了子系統的安全性。 缺點:業務一旦出現變更,就需要直接修改外觀類。
享元模式
使用共享物件有效地支援大量細粒度的物件。
該模式下的物件有
- Flyweight:抽象享元角色。
- ConcreteFlyweight:具體享元角色
- FlyweightFactory:享元工廠,負責物件建立和管理。
其實往簡單了說就是一種緩衝池的技術。
/**
* 享元工廠
*/
public class VipFactory {
private static Map<String, Vip> cache = new HashMap<>();
public static Vip getVip(String number){
if(cache.containsKey(number)){
return cache.get(number);
}else{
Vip vip = new Vip(number);
cache.put(number, vip);
return vip;
}
}
}
/**
* 享元角色
*/
public class Vip implements IVip {
private String name;
private String number;
Vip(String number){
this.number = number;
}
@Override
public void showVip(String number) {
if (number.equals(number)) {
System.out.println(name == null? "空": name);
}
}
}
/**
* 享元抽象角色
*/
public interface IVip {
void showVip(String number);
}
複製程式碼
在享元工廠中我們顯而易見的看到了由static
修飾的cache
變數,這就是一個緩衝,如果緩衝中存在,就從緩衝中取,不存在則建立。
以上就是我的學習成果,如果有什麼我沒有思考到的地方或是文章記憶體在錯誤,歡迎與我分享。
相關文章推薦: