結構型模式主要關注類或對象的組合,旨在通過識別簡單的結構關系來設計更復雜的結構。以下是幾種常見的結構型設計模式:
1. 適配器模式(Adapter Pattern)
-
- 將一個類的接口轉換成客戶端所期望的另一個接口,使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
- 適用于需要使用現有類但其接口不符合需求的情況。
假設我們有一個舊的MediaPlayer
接口,它只能播放.mp3
文件。現在我們需要一個新功能,能夠播放.wav
格式的文件。我們可以使用適配器模式來解決這個問題。
// 已有的MediaPlayer接口
interface MediaPlayer {void play(String audioType, String fileName);
}// 實現了MediaPlayer接口的類
class AudioPlayer implements MediaPlayer {@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("mp3")) {System.out.println("Playing mp3 file. Name: " + fileName);} else {System.out.println("Invalid media. " + audioType + " format not supported");}}
}// 新的AdvancedMediaPlayer接口及其實現類
interface AdvancedMediaPlayer {void playWav(String fileName);
}class WavPlayer implements AdvancedMediaPlayer {@Overridepublic void playWav(String fileName) {System.out.println("Playing wav file. Name: " + fileName);}
}// 創建適配器類
class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter() {advancedMusicPlayer = new WavPlayer();}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("wav")) {advancedMusicPlayer.playWav(fileName);}}
}// 使用適配器
public class AdapterPatternDemo {public static void main(String[] args) {MediaPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "song.mp3");audioPlayer.play("wav", "song.wav"); // 這里會顯示不支持MediaPlayer mediaAdapter = new MediaAdapter();mediaAdapter.play("wav", "song.wav"); // 現在可以播放wav文件}
}
2. 橋接模式(Bridge Pattern)
-
- 將抽象部分與它的實現部分分離,使它們都可以獨立變化。
- 適用于當不想在抽象和實現之間建立固定的綁定關系時,例如圖形庫中形狀和顏色的組合。
假設我們有一個繪圖應用程序,它可以繪制不同形狀,并且這些形狀可以用不同的顏色繪制。為了使形狀和顏色獨立變化,我們可以使用橋接模式。
// 顏色接口
interface Color {void applyColor();
}// 具體的顏色實現
class RedColor implements Color {@Overridepublic void applyColor() {System.out.println("Red color applied.");}
}class BlueColor implements Color {@Overridepublic void applyColor() {System.out.println("Blue color applied.");}
}// 抽象的形狀類,持有Color對象的引用
abstract class Shape {protected Color color;public Shape(Color color) {this.color = color;}abstract void draw();
}// 具體的形狀實現
class Circle extends Shape {public Circle(Color color) {super(color);}@Overridevoid draw() {System.out.print("Drawing Circle. ");color.applyColor();}
}// 使用橋接模式
public class BridgePatternDemo {public static void main(String[] args) {Shape redCircle = new Circle(new RedColor());redCircle.draw(); // 輸出:Drawing Circle. Red color applied.Shape blueCircle = new Circle(new BlueColor());blueCircle.draw(); // 輸出:Drawing Circle. Blue color applied.}
}
3. 組合模式(Composite Pattern)
-
- 允許將對象組合成樹形結構以表示“部分-整體”的層次結構,使得用戶對單個對象和組合對象的使用具有一致性。
- 常用于文件系統、菜單等層次化結構的場景。
假設我們有一個組織結構,包括員工和部門。每個部門可能包含多個員工和其他部門。我們可以使用組合模式來處理這種“部分-整體”的層次結構。
// 組件接口
interface Employee {void showEmployeeDetails();
}// 葉子節點
class Developer implements Employee {private String name;private long empId;public Developer(String name, long empId) {this.name = name;this.empId = empId;}@Overridepublic void showEmployeeDetails() {System.out.println("Developer Name: " + name + ", EmpId: " + empId);}
}// 組合部件
class Manager implements Employee {private List<Employee> employees = new ArrayList<>();public void addEmployee(Employee emp) {employees.add(emp);}public void removeEmployee(Employee emp) {employees.remove(emp);}@Overridepublic void showEmployeeDetails() {for (Employee emp : employees) {emp.showEmployeeDetails();}}
}// 使用組合模式
public class CompositePatternDemo {public static void main(String[] args) {Employee dev1 = new Developer("John", 1001L);Employee dev2 = new Developer("Jane", 1002L);Manager manager = new Manager();manager.addEmployee(dev1);manager.addEmployee(dev2);Employee dev3 = new Developer("Doe", 1003L);manager.addEmployee(dev3);manager.showEmployeeDetails();}
}
4. 裝飾模式(Decorator Pattern)
-
- 動態地給一個對象添加一些額外的職責,就增加功能來說,比生成子類更為靈活。
- 適用于需要動態地為對象添加功能而不改變原有代碼的情況,如Java中的I/O流。
裝飾模式允許你通過創建一個包裝對象動態地向一個對象添加功能,而不需要修改其結構。
// 基礎組件接口
interface Coffee {double getCost(); // 獲取成本String getDescription(); // 獲取描述
}// 具體組件實現
class SimpleCoffee implements Coffee {@Overridepublic double getCost() { return 10; } // 簡單咖啡的成本@Overridepublic String getDescription() { return "Simple Coffee"; }
}// 裝飾器抽象類
abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee c) {this.decoratedCoffee = c;}@Overridepublic double getCost() { return decoratedCoffee.getCost(); }@Overridepublic String getDescription() { return decoratedCoffee.getDescription(); }
}// 牛奶裝飾器
class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee c) { super(c); }@Overridepublic double getCost() { return super.getCost() + 2; }@Overridepublic String getDescription() { return super.getDescription() + ", Milk"; }
}// 使用裝飾模式
public class DecoratorPatternDemo {public static void main(String[] args) {Coffee myCoffee = new MilkDecorator(new SimpleCoffee());System.out.println("Cost: " + myCoffee.getCost());System.out.println("Description: " + myCoffee.getDescription());}
}
5. 外觀模式(Facade Pattern)
-
- 為子系統中的一組接口提供一個一致的界面,定義了一個高層接口,這個接口使得這一子系統更加容易使用。
- 適用于簡化復雜系統的接口,如數據庫連接管理。
外觀模式提供了一個統一的接口,用來訪問子系統中的一群接口。它提供了一個高層次的接口,使得子系統更易于使用。
// 子系統類
class CPU {public void processData() { System.out.println("Processing data."); }
}class Memory {public void load() { System.out.println("Loading data from memory."); }
}class HardDrive {public void readData() { System.out.println("Reading data from hard drive."); }
}// 外觀類
class ComputerFacade {private CPU cpu;private Memory memory;private HardDrive hardDrive;public ComputerFacade() {this.cpu = new CPU();this.memory = new Memory();this.hardDrive = new HardDrive();}public void startComputer() {memory.load();hardDrive.readData();cpu.processData();}
}// 使用外觀模式
public class FacadePatternDemo {public static void main(String[] args) {ComputerFacade computer = new ComputerFacade();computer.startComputer();}
}
6. 享元模式(Flyweight Pattern)
-
- 運用共享技術有效地支持大量細粒度的對象。
- 適用于需要創建大量相似對象且內存占用成為問題的情況,如文本編輯器中的字符對象。
享元模式主要用于減少創建對象的數量,以減少內存占用和提高性能。它通過共享盡可能多的對象來做到這一點。
// 享元接口
interface Shape {void draw(String color);
}// 具體享元類
class Circle implements Shape {private String color;public Circle(String color) {this.color = color;}@Overridepublic void draw(String fillColor) {System.out.println("Drawing Circle [Color: " + color + ", FillColor: " + fillColor + "]");}
}// 享元工廠
class ShapeFactory {private static final HashMap<String, Shape> circleMap = new HashMap<>();public static Shape getCircle(String color) {Circle circle = (Circle)circleMap.get(color);if(circle == null) {circle = new Circle(color);circleMap.put(color, circle);System.out.println("Creating circle of color: " + color);}return circle;}
}// 使用享元模式
public class FlyweightPatternDemo {public static void main(String[] args) {ShapeFactory shapeFactory = new ShapeFactory();Shape shape1 = shapeFactory.getCircle("Red");shape1.draw("Dark Red");Shape shape2 = shapeFactory.getCircle("Red"); // 不會創建新對象shape2.draw("Light Red");}
}
7. 代理模式(Proxy Pattern)
-
- 為其他對象提供一種代理以控制對這個對象的訪問。
- 適用于需要在訪問對象時加入額外處理邏輯的情況,如遠程調用、權限檢查等。
代理模式為其他對象提供一種代理以控制對這個對象的訪問。
// 主題接口
interface Image {void display();
}// 真實主題類
class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadFromDisk(fileName);}@Overridepublic void display() {System.out.println("Displaying " + fileName);}private void loadFromDisk(String fileName) {System.out.println("Loading " + fileName);}
}// 代理類
class ProxyImage implements Image {private RealImage realImage;private String fileName;public ProxyImage(String fileName) {this.fileName = fileName;}@Overridepublic void display() {if(realImage == null) {realImage = new RealImage(fileName);}realImage.display();}
}// 使用代理模式
public class ProxyPatternDemo {public static void main(String[] args) {Image image = new ProxyImage("test_10mb.jpg");// 圖像將從磁盤加載image.display();System.out.println("");// 圖像不會從磁盤加載image.display();}
}