- 設計模式教程
- 設計模式 - 首頁
- 設計模式 - 概述
- 設計模式 - 工廠模式
- 抽象工廠模式
- 設計模式 - 單例模式
- 設計模式 - 建造者模式
- 設計模式 - 原型模式
- 設計模式 - 介面卡模式
- 設計模式 - 橋接模式
- 設計模式 - 過濾器模式
- 設計模式 - 組合模式
- 設計模式 - 裝飾器模式
- 設計模式 - 外觀模式
- 設計模式 - 享元模式
- 設計模式 - 代理模式
- 責任鏈模式
- 設計模式 - 命令模式
- 設計模式 - 直譯器模式
- 設計模式 - 迭代器模式
- 設計模式 - 中介者模式
- 設計模式 - 備忘錄模式
- 設計模式 - 觀察者模式
- 設計模式 - 狀態模式
- 設計模式 - 空物件模式
- 設計模式 - 策略模式
- 設計模式 - 模板模式
- 設計模式 - 訪問者模式
- 設計模式 - MVC 模式
- 業務代表模式
- 組合實體模式
- 資料訪問物件模式
- 前端控制器模式
- 攔截過濾器模式
- 服務定位器模式
- 傳輸物件模式
- 設計模式資源
- 設計模式 - 問答
- 設計模式 - 速查
- 設計模式 - 有用資源
- 設計模式 - 討論
設計模式速查
設計模式代表了經驗豐富的面向物件軟體開發人員使用的最佳實踐。設計模式是對軟體開發人員在軟體開發過程中遇到的常見問題的解決方案。這些解決方案是眾多軟體開發人員在相當長的一段時間內透過反覆試驗獲得的。
什麼是四人幫 (GOF)?
1994年,四位作者 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 出版了一本書,名為設計模式 - 可複用面向物件軟體的基礎,該書開啟了軟體開發中設計模式的概念。
這些作者統稱為四人幫 (GOF)。根據這些作者的說法,設計模式主要基於以下面向物件設計的原則。
面向介面程式設計,而非面向實現
優先使用物件組合而非類繼承
設計模式的用法
設計模式在軟體開發中主要有兩個用途。
為開發人員提供一個共同的平臺
設計模式提供標準術語,並針對特定場景。例如,單例設計模式表示使用單個物件,因此所有熟悉單例設計模式的開發人員都將使用單個物件,他們可以互相告知程式遵循單例模式。
最佳實踐
設計模式經過長時間的演變,它們為軟體開發過程中遇到的某些問題提供了最佳解決方案。學習這些模式可以幫助沒有經驗的開發人員輕鬆快速地學習軟體設計。
設計模式的型別
根據設計模式參考書設計模式 - 可複用面向物件軟體的基礎,共有23種設計模式。這些模式可以分為三類:建立型、結構型和行為型模式。我們還將討論另一類設計模式:J2EE 設計模式。
| 序號 | 模式及描述 |
|---|---|
| 1 | 建立型模式 這些設計模式提供了一種建立物件的方式,同時隱藏了建立邏輯,而不是直接使用 new 運算子例項化物件。這使程式在決定為給定用例需要建立哪些物件時具有更大的靈活性。 |
| 2 | 結構型模式 這些設計模式關注類和物件的組合。繼承的概念用於組合介面並定義組合物件以獲得新功能的方法。 |
| 3 | 行為型模式 這些設計模式專門關注物件之間的通訊。 |
| 4 | J2EE 模式 這些設計模式專門關注表示層。這些模式由 Sun Java 中心確定。 |
工廠模式
工廠模式是 Java 中最常用的設計模式之一。這種設計模式屬於建立型模式,因為它提供了一種建立物件的最佳方法。
在工廠模式中,我們建立物件而不向客戶端公開建立邏輯,並使用公共介面引用新建立的物件。
實現
我們將建立一個Shape介面和實現Shape介面的具體類。接下來定義一個工廠類ShapeFactory。
我們的演示類FactoryPatternDemo將使用ShapeFactory來獲取Shape物件。它將資訊(CIRCLE / RECTANGLE / SQUARE)傳遞給ShapeFactory以獲取其所需的 物件型別。
步驟 1
建立一個介面。
Shape.java
public interface Shape {
void draw();
}
步驟 2
建立實現同一介面的具體類。
Rectangle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
Square.java
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
Circle.java
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
步驟 3
建立一個工廠,根據給定的資訊生成具體類的物件。
ShapeFactory.java
public class ShapeFactory {
//use getShape method to get object of type shape
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
步驟 4
使用工廠透過傳遞資訊(例如型別)來獲取具體類的物件。
FactoryPatternDemo.java
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//get an object of Circle and call its draw method.
Shape shape1 = shapeFactory.getShape("CIRCLE");
//call draw method of Circle
shape1.draw();
//get an object of Rectangle and call its draw method.
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//call draw method of Rectangle
shape2.draw();
//get an object of Square and call its draw method.
Shape shape3 = shapeFactory.getShape("SQUARE");
//call draw method of square
shape3.draw();
}
}
步驟 5
驗證輸出。
Inside Circle::draw() method. Inside Rectangle::draw() method. Inside Square::draw() method.
設計模式 - 抽象工廠模式
抽象工廠模式圍繞一個超級工廠工作,該超級工廠建立其他工廠。這個工廠也稱為工廠的工廠。這種設計模式屬於建立型模式,因為它提供了一種建立物件的最佳方法。
在抽象工廠模式中,一個介面負責建立相關物件的工廠,而無需明確指定它們的類。每個生成的工廠都可以根據工廠模式提供物件。
實現
我們將建立一個 Shape 介面和一個實現它的具體類。下一步,我們建立一個抽象工廠類 AbstractFactory。定義工廠類 ShapeFactory,它擴充套件 AbstractFactory。建立工廠建立者/生成器類 FactoryProducer。
我們的演示類 AbstractFactoryPatternDemo 使用 FactoryProducer 獲取 AbstractFactory 物件。它將資訊(CIRCLE / RECTANGLE / SQUARE 用於 Shape)傳遞給 AbstractFactory 以獲取其所需的 物件型別。
步驟 1
為形狀建立介面。
Shape.java
public interface Shape {
void draw();
}
步驟 2
建立實現同一介面的具體類。
RoundedRectangle.java
public class RoundedRectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside RoundedRectangle::draw() method.");
}
}
RoundedSquare.java
public class RoundedSquare implements Shape {
@Override
public void draw() {
System.out.println("Inside RoundedSquare::draw() method.");
}
}
Rectangle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
步驟 3
建立一個抽象類以獲取普通形狀物件和圓角形狀物件的工廠。
AbstractFactory.java
public abstract class AbstractFactory {
abstract Shape getShape(String shapeType) ;
}
步驟 4
建立擴充套件 AbstractFactory 的工廠類,以根據給定的資訊生成具體類的物件。
ShapeFactory.java
public class ShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
}else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
RoundedShapeFactory.java
public class RoundedShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new RoundedRectangle();
}else if(shapeType.equalsIgnoreCase("SQUARE")){
return new RoundedSquare();
}
return null;
}
}
步驟 5
建立一個工廠生成器/生產者類,透過傳遞資訊(如 Shape)來獲取工廠。
FactoryProducer.java
public class FactoryProducer {
public static AbstractFactory getFactory(boolean rounded){
if(rounded){
return new RoundedShapeFactory();
}else{
return new ShapeFactory();
}
}
}
步驟 6
使用 FactoryProducer 獲取 AbstractFactory,以便透過傳遞資訊(如型別)來獲取具體類的工廠。
AbstractFactoryPatternDemo.java
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
//get shape factory
AbstractFactory shapeFactory = FactoryProducer.getFactory(false);
//get an object of Shape Rectangle
Shape shape1 = shapeFactory.getShape("RECTANGLE");
//call draw method of Shape Rectangle
shape1.draw();
//get an object of Shape Square
Shape shape2 = shapeFactory.getShape("SQUARE");
//call draw method of Shape Square
shape2.draw();
//get shape factory
AbstractFactory shapeFactory1 = FactoryProducer.getFactory(true);
//get an object of Shape Rectangle
Shape shape3 = shapeFactory1.getShape("RECTANGLE");
//call draw method of Shape Rectangle
shape3.draw();
//get an object of Shape Square
Shape shape4 = shapeFactory1.getShape("SQUARE");
//call draw method of Shape Square
shape4.draw();
}
}
步驟 7
驗證輸出。
Inside Rectangle::draw() method. Inside Square::draw() method. Inside RoundedRectangle::draw() method. Inside RoundedSquare::draw() method.
單例模式
單例模式是 Java 中最簡單的設計模式之一。這種設計模式屬於建立型模式,因為它提供了一種建立物件的最佳方法。
此模式涉及單個類,該類負責建立自己的物件,同時確保只建立單個物件。此類提供了一種訪問其唯一物件的方式,可以直接訪問而無需例項化類的物件。
實現
我們將建立一個SingleObject類。SingleObject類的建構函式是私有的,並且具有自身的靜態例項。
SingleObject類提供了一種靜態方法,用於將靜態例項提供給外部世界。我們的演示類SingletonPatternDemo將使用SingleObject類來獲取SingleObject物件。
步驟 1
建立一個單例類。
SingleObject.java
public class SingleObject {
//create an object of SingleObject
private static SingleObject instance = new SingleObject();
//make the constructor private so that this class cannot be
//instantiated
private SingleObject(){}
//Get the only object available
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
步驟 2
從單例類獲取唯一物件。
SingletonPatternDemo.java
public class SingletonPatternDemo {
public static void main(String[] args) {
//illegal construct
//Compile Time Error: The constructor SingleObject() is not visible
//SingleObject object = new SingleObject();
//Get the only object available
SingleObject object = SingleObject.getInstance();
//show the message
object.showMessage();
}
}
步驟 3
驗證輸出。
Hello World!
建造者模式
建造者模式使用簡單的物件和逐步的方法構建複雜的物件。這種設計模式屬於建立型模式,因為它提供了一種建立物件的最佳方法。
建造者類逐步構建最終物件。此建造者獨立於其他物件。
實現
我們考慮了快餐店的業務案例,其中典型的餐點可能是漢堡和冷飲。漢堡可以是素食漢堡或雞肉漢堡,並用包裝紙包裝。冷飲可以是可樂或百事可樂,並裝在瓶子裡。
我們將建立一個Item介面,表示漢堡和冷飲等食物,以及實現Item介面的具體類,以及一個Packing介面,表示食物的包裝,以及實現Packing介面的具體類,例如漢堡將用包裝紙包裝,冷飲將裝在瓶子裡。
然後,我們建立一個Meal類,其中包含Item的ArrayList,以及一個MealBuilder,用於透過組合Item來構建不同型別的Meal物件。我們的演示類BuilderPatternDemo將使用MealBuilder來構建一個Meal。
步驟 1
建立一個表示食物和包裝的介面 Item。
Item.java
public interface Item {
public String name();
public Packing packing();
public float price();
}
Packing.java
public interface Packing {
public String pack();
}
步驟 2
建立實現 Packing 介面的具體類。
Wrapper.java
public class Wrapper implements Packing {
@Override
public String pack() {
return "Wrapper";
}
}
Bottle.java
public class Bottle implements Packing {
@Override
public String pack() {
return "Bottle";
}
}
步驟 3
建立實現 Item 介面的抽象類,提供預設功能。
Burger.java
public abstract class Burger implements Item {
@Override
public Packing packing() {
return new Wrapper();
}
@Override
public abstract float price();
}
ColdDrink.java
public abstract class ColdDrink implements Item {
@Override
public Packing packing() {
return new Bottle();
}
@Override
public abstract float price();
}
步驟 4
建立擴充套件 Burger 和 ColdDrink 類的具體類
VegBurger.java
public class VegBurger extends Burger {
@Override
public float price() {
return 25.0f;
}
@Override
public String name() {
return "Veg Burger";
}
}
ChickenBurger.java
public class ChickenBurger extends Burger {
@Override
public float price() {
return 50.5f;
}
@Override
public String name() {
return "Chicken Burger";
}
}
Coke.java
public class Coke extends ColdDrink {
@Override
public float price() {
return 30.0f;
}
@Override
public String name() {
return "Coke";
}
}
Pepsi.java
public class Pepsi extends ColdDrink {
@Override
public float price() {
return 35.0f;
}
@Override
public String name() {
return "Pepsi";
}
}
步驟 5
建立一個 Meal 類,其中定義了上述 Item 物件。
Meal.java
import java.util.ArrayList;
import java.util.List;
public class Meal {
private List<Item> items = new ArrayList<Item>();
public void addItem(Item item){
items.add(item);
}
public float getCost(){
float cost = 0.0f;
for (Item item : items) {
cost += item.price();
}
return cost;
}
public void showItems(){
for (Item item : items) {
System.out.print("Item : "+item.name());
System.out.print(", Packing : "+item.packing().pack());
System.out.println(", Price : "+item.price());
}
}
}
步驟 6
建立一個 MealBuilder 類,這是負責建立 Meal 物件的實際建造者類。
MealBuilder.java
public class MealBuilder {
public Meal prepareVegMeal (){
Meal meal = new Meal();
meal.addItem(new VegBurger());
meal.addItem(new Coke());
return meal;
}
public Meal prepareNonVegMeal (){
Meal meal = new Meal();
meal.addItem(new ChickenBurger());
meal.addItem(new Pepsi());
return meal;
}
}
步驟 7
BuiderPatternDemo 使用 MealBuider 演示建造者模式。
BuilderPatternDemo.java
public class BuilderPatternDemo {
public static void main(String[] args) {
MealBuilder mealBuilder = new MealBuilder();
Meal vegMeal = mealBuilder.prepareVegMeal();
System.out.println("Veg Meal");
vegMeal.showItems();
System.out.println("Total Cost: " +vegMeal.getCost());
Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
System.out.println("\n\nNon-Veg Meal");
nonVegMeal.showItems();
System.out.println("Total Cost: " +nonVegMeal.getCost());
}
}
步驟 8
驗證輸出。
Veg Meal Item : Veg Burger, Packing : Wrapper, Price : 25.0 Item : Coke, Packing : Bottle, Price : 30.0 Total Cost: 55.0 Non-Veg Meal Item : Chicken Burger, Packing : Wrapper, Price : 50.5 Item : Pepsi, Packing : Bottle, Price : 35.0 Total Cost: 85.5
原型模式
原型模式指的是在考慮效能的情況下建立重複物件。這種設計模式屬於建立型模式,因為它提供了一種建立物件的最佳方法。
此模式涉及實現一個原型介面,該介面指示建立當前物件的克隆。當直接建立物件成本很高時,可以使用此模式。例如,物件需要在代價高昂的資料庫操作之後建立。我們可以快取物件,在下次請求時返回其克隆,並在需要時更新資料庫,從而減少資料庫呼叫次數。
實現
我們將建立一個抽象類Shape和擴充套件Shape類的具體類。下一步定義一個ShapeCache類,它將形狀物件儲存在Hashtable中,並在請求時返回它們的克隆。
我們的演示類PrototypPatternDemo將使用ShapeCache類獲取Shape物件。
步驟 1
建立一個實現Clonable介面的抽象類。
Shape.java
public abstract class Shape implements Cloneable {
private String id;
protected String type;
abstract void draw();
public String getType(){
return type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
步驟 2
建立擴充套件上述類的具體類。
Rectangle.java
public class Rectangle extends Shape {
public Rectangle(){
type = "Rectangle";
}
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
Square.java
public class Square extends Shape {
public Square(){
type = "Square";
}
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
Circle.java
public class Circle extends Shape {
public Circle(){
type = "Circle";
}
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
步驟 3
建立一個類,從資料庫獲取具體類並將它們儲存在Hashtable中。
ShapeCache.java
import java.util.Hashtable;
public class ShapeCache {
private static Hashtable<String, Shape> shapeMap
= new Hashtable<String, Shape>();
public static Shape getShape(String shapeId) {
Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
}
// for each shape run database query and create shape
// shapeMap.put(shapeKey, shape);
// for example, we are adding three shapes
public static void loadCache() {
Circle circle = new Circle();
circle.setId("1");
shapeMap.put(circle.getId(),circle);
Square square = new Square();
square.setId("2");
shapeMap.put(square.getId(),square);
Rectangle rectangle = new Rectangle();
rectangle.setId("3");
shapeMap.put(rectangle.getId(),rectangle);
}
}
步驟 4
PrototypePatternDemo使用ShapeCache類獲取儲存在Hashtable中的形狀的克隆。
PrototypePatternDemo.java
public class PrototypePatternDemo {
public static void main(String[] args) {
ShapeCache.loadCache();
Shape clonedShape = (Shape) ShapeCache.getShape("1");
System.out.println("Shape : " + clonedShape.getType());
Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
System.out.println("Shape : " + clonedShape2.getType());
Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
System.out.println("Shape : " + clonedShape3.getType());
}
}
步驟 5
驗證輸出。
Shape : Circle Shape : Square Shape : Rectangle
介面卡模式 (Adapter Pattern)
介面卡模式作為兩個不相容介面之間的橋樑。這種設計模式屬於結構型模式,因為它組合了兩個獨立介面的功能。
此模式涉及一個類,負責連線獨立或不相容介面的功能。一個現實生活中的例子是讀卡器,它充當儲存卡和筆記型電腦之間的介面卡。您可以將儲存卡插入讀卡器,然後將讀卡器插入筆記型電腦,以便透過筆記型電腦讀取儲存卡。
我們將透過以下示例演示介面卡模式的使用,其中一個音訊播放器裝置只能播放mp3檔案,並希望使用能夠播放vlc和mp4檔案的更高階的音訊播放器。
實現
我們有一個介面MediaPlayer介面和一個實現MediaPlayer介面的具體類AudioPlayer。AudioPlayer預設可以播放mp3格式的音訊檔案。
我們還有另一個介面AdvancedMediaPlayer和實現AdvancedMediaPlayer介面的具體類。這些類可以播放vlc和mp4格式的檔案。
我們希望使AudioPlayer也能播放其他格式。為此,我們建立了一個介面卡類MediaAdapter,它實現了MediaPlayer介面並使用AdvancedMediaPlayer物件播放所需的格式。
AudioPlayer使用介面卡類MediaAdapter,將所需的音訊型別傳遞給它,而無需知道可以播放所需格式的實際類。我們的演示類AdapterPatternDemo將使用AudioPlayer類播放各種格式。
步驟 1
為媒體播放器和高階媒體播放器建立介面。
MediaPlayer.java
public interface MediaPlayer {
public void play(String audioType, String fileName);
}
AdvancedMediaPlayer.java
public interface AdvancedMediaPlayer {
public void playVlc(String fileName);
public void playMp4(String fileName);
}
步驟 2
建立實現AdvancedMediaPlayer介面的具體類。
VlcPlayer.java
public class VlcPlayer implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
@Override
public void playMp4(String fileName) {
//do nothing
}
}
Mp4Player.java
public class Mp4Player implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
//do nothing
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}
步驟 3
建立實現MediaPlayer介面的介面卡類。
MediaAdapter.java
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMp4(fileName);
}
}
}
步驟 4
建立實現MediaPlayer介面的具體類。
AudioPlayer.java
public class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
//inbuilt support to play mp3 music files
if(audioType.equalsIgnoreCase("mp3")){
System.out.println("Playing mp3 file. Name: "+ fileName);
}
//mediaAdapter is providing support to play other file formats
else if(audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else{
System.out.println("Invalid media. "+
audioType + " format not supported");
}
}
}
步驟 5
使用AudioPlayer播放不同型別的音訊格式。
AdapterPatternDemo.java
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
步驟 6
驗證輸出。
Playing mp3 file. Name: beyond the horizon.mp3 Playing mp4 file. Name: alone.mp4 Playing vlc file. Name: far far away.vlc Invalid media. avi format not supported
橋接模式 (Bridge Pattern)
橋接模式用於我們需要將抽象與其實現解耦的情況,以便兩者可以獨立變化。這種設計模式屬於結構型模式,因為它透過提供一個橋接結構來解耦實現類和抽象類。
此模式涉及一個充當橋樑的介面,它使具體類的功能獨立於介面實現類。兩種型別的類可以在結構上進行更改,而不會相互影響。
我們將透過以下示例演示橋接模式的使用,其中可以使用相同的抽象類方法但在不同的橋接實現類中繪製不同顏色的圓。
實現
我們有一個介面DrawAPI介面,它充當橋接實現器,以及實現DrawAPI介面的具體類RedCircle、GreenCircle。Shape是一個抽象類,並將使用DrawAPI的物件。我們的演示類BridgePatternDemo將使用Shape類繪製不同顏色的圓。
步驟 1
建立橋接實現器介面。
DrawAPI.java
public interface DrawAPI {
public void drawCircle(int radius, int x, int y);
}
步驟 2
建立實現DrawAPI介面的具體橋接實現類。
RedCircle.java
public class RedCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: red, radius: "
+ radius +", x: " +x+", "+ y +"]");
}
}
GreenCircle.java
public class GreenCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: green, radius: "
+ radius +", x: " +x+", "+ y +"]");
}
}
步驟 3
使用DrawAPI介面建立一個抽象類Shape。
Shape.java
public abstract class Shape {
protected DrawAPI drawAPI;
protected Shape(DrawAPI drawAPI){
this.drawAPI = drawAPI;
}
public abstract void draw();
}
步驟 4
建立實現Shape介面的具體類。
Circle.java
public class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawAPI.drawCircle(radius,x,y);
}
}
步驟 5
使用Shape和DrawAPI類繪製不同顏色的圓。
BridgePatternDemo.java
public class BridgePatternDemo {
public static void main(String[] args) {
Shape redCircle = new Circle(100,100, 10, new RedCircle());
Shape greenCircle = new Circle(100,100, 10, new GreenCircle());
redCircle.draw();
greenCircle.draw();
}
}
步驟 6
驗證輸出。
Drawing Circle[ color: red, radius: 10, x: 100, 100] Drawing Circle[ color: green, radius: 10, x: 100, 100]
過濾器/標準模式 (Filter/Criteria Pattern)
過濾器模式或標準模式是一種設計模式,它使開發人員能夠使用不同的標準過濾一組物件,並透過邏輯運算以解耦的方式將它們連結起來。這種設計模式屬於結構型模式,因為它組合了多個標準以獲得單個標準。
實現
我們將建立一個Person物件、Criteria介面和實現此介面的具體類,以過濾Person物件的列表。我們的演示類CriteriaPatternDemo使用Criteria物件根據各種標準及其組合來過濾Person物件的列表。
步驟 1
建立一個要應用標準的類。
Person.java
public class Person {
private String name;
private String gender;
private String maritalStatus;
public Person(String name,String gender,String maritalStatus){
this.name = name;
this.gender = gender;
this.maritalStatus = maritalStatus;
}
public String getName() {
return name;
}
public String getGender() {
return gender;
}
public String getMaritalStatus() {
return maritalStatus;
}
}
步驟 2
為Criteria建立介面。
Criteria.java
import java.util.List;
public interface Criteria {
public List<Person> meetCriteria(List<Person> persons);
}
步驟 3
建立實現Criteria介面的具體類。
CriteriaMale.java
import java.util.ArrayList;
import java.util.List;
public class CriteriaMale implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> malePersons = new ArrayList<Person>();
for (Person person : persons) {
if(person.getGender().equalsIgnoreCase("MALE")){
malePersons.add(person);
}
}
return malePersons;
}
}
CriteriaFemale.java
import java.util.ArrayList;
import java.util.List;
public class CriteriaFemale implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> femalePersons = new ArrayList<Person>();
for (Person person : persons) {
if(person.getGender().equalsIgnoreCase("FEMALE")){
femalePersons.add(person);
}
}
return femalePersons;
}
}
CriteriaSingle.java
import java.util.ArrayList;
import java.util.List;
public class CriteriaSingle implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> singlePersons = new ArrayList<Person>();
for (Person person : persons) {
if(person.getMaritalStatus().equalsIgnoreCase("SINGLE")){
singlePersons.add(person);
}
}
return singlePersons;
}
}
AndCriteria.java
import java.util.List;
public class AndCriteria implements Criteria {
private Criteria criteria;
private Criteria otherCriteria;
public AndCriteria(Criteria criteria, Criteria otherCriteria) {
this.criteria = criteria;
this.otherCriteria = otherCriteria;
}
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> firstCriteriaPersons = criteria.meetCriteria(persons);
return otherCriteria.meetCriteria(firstCriteriaPersons);
}
}
OrCriteria.java
import java.util.List;
public class AndCriteria implements Criteria {
private Criteria criteria;
private Criteria otherCriteria;
public AndCriteria(Criteria criteria, Criteria otherCriteria) {
this.criteria = criteria;
this.otherCriteria = otherCriteria;
}
@Override
public List<Person> meetCriteria(List<Person> persons) {
List<Person> firstCriteriaItems = criteria.meetCriteria(persons);
List<Person> otherCriteriaItems = otherCriteria.meetCriteria(persons);
for (Person person : otherCriteriaItems) {
if(!firstCriteriaItems.contains(person)){
firstCriteriaItems.add(person);
}
}
return firstCriteriaItems;
}
}
步驟4
使用不同的Criteria及其組合來過濾人員。
CriteriaPatternDemo.java
import java.util.ArrayList;
import java.util.List;
public class CriteriaPatternDemo {
public static void main(String[] args) {
List<Person> persons = new ArrayList<Person>();
persons.add(new Person("Robert","Male", "Single"));
persons.add(new Person("John","Male", "Married"));
persons.add(new Person("Laura","Female", "Married"));
persons.add(new Person("Diana","Female", "Single"));
persons.add(new Person("Mike","Male", "Single"));
persons.add(new Person("Bobby","Male", "Single"));
Criteria male = new CriteriaMale();
Criteria female = new CriteriaFemale();
Criteria single = new CriteriaSingle();
Criteria singleMale = new AndCriteria(single, male);
Criteria singleOrFemale = new OrCriteria(single, female);
System.out.println("Males: ");
printPersons(male.meetCriteria(persons));
System.out.println("\nFemales: ");
printPersons(female.meetCriteria(persons));
System.out.println("\nSingle Males: ");
printPersons(singleMale.meetCriteria(persons));
System.out.println("\nSingle Or Females: ");
printPersons(singleOrFemale.meetCriteria(persons));
}
public static void printPersons(List<Person> persons){
for (Person person : persons) {
System.out.println("Person : [ Name : " + person.getName()
+", Gender : " + person.getGender()
+", Marital Status : " + person.getMaritalStatus()
+" ]");
}
}
}
步驟 5
驗證輸出。
Males: Person : [ Name : Robert, Gender : Male, Marital Status : Single ] Person : [ Name : John, Gender : Male, Marital Status : Married ] Person : [ Name : Mike, Gender : Male, Marital Status : Single ] Person : [ Name : Bobby, Gender : Male, Marital Status : Single ] Females: Person : [ Name : Laura, Gender : Female, Marital Status : Married ] Person : [ Name : Diana, Gender : Female, Marital Status : Single ] Single Males: Person : [ Name : Robert, Gender : Male, Marital Status : Single ] Person : [ Name : Mike, Gender : Male, Marital Status : Single ] Person : [ Name : Bobby, Gender : Male, Marital Status : Single ] Single Or Females: Person : [ Name : Robert, Gender : Male, Marital Status : Single ] Person : [ Name : Diana, Gender : Female, Marital Status : Single ] Person : [ Name : Mike, Gender : Male, Marital Status : Single ] Person : [ Name : Bobby, Gender : Male, Marital Status : Single ] Person : [ Name : Laura, Gender : Female, Marital Status : Married ]
組合模式 (Composite Pattern)
組合模式用於我們需要以類似於單個物件的方式處理一組物件的情況。組合模式根據樹結構組成物件,以表示部分和整體層次結構。這種設計模式屬於結構型模式,因為它建立一組物件的樹結構。
此模式建立一個類,其中包含其自身物件組。此類提供修改其相同物件組的方法。
我們將透過以下示例演示組合模式的使用,該示例顯示了一個組織的員工層次結構。
實現
我們有一個類Employee,它充當組合模式參與者類。我們的演示類CompositePatternDemo將使用Employee類新增部門級別層次結構並列印所有員工。
步驟 1
建立包含Employee物件列表的Employee類。
Employee.java
import java.util.ArrayList;
import java.util.List;
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates;
// constructor
public Employee(String name,String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}
public void add(Employee e) {
subordinates.add(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
public List<Employee> getSubordinates(){
return subordinates;
}
public String toString(){
return ("Employee :[ Name : "+ name
+", dept : "+ dept + ", salary :"
+ salary+" ]");
}
}
步驟 2
使用Employee類建立和列印員工層次結構。
CompositePatternDemo.java
public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", 30000);
Employee headSales = new Employee("Robert","Head Sales", 20000);
Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
Employee clerk1 = new Employee("Laura","Marketing", 10000);
Employee clerk2 = new Employee("Bob","Marketing", 10000);
Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
CEO.add(headSales);
CEO.add(headMarketing);
headSales.add(salesExecutive1);
headSales.add(salesExecutive2);
headMarketing.add(clerk1);
headMarketing.add(clerk2);
//print all employees of the organization
System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
System.out.println(employee);
}
}
}
}
步驟 3
驗證輸出。
Employee :[ Name : John, dept : CEO, salary :30000 ] Employee :[ Name : Robert, dept : Head Sales, salary :20000 ] Employee :[ Name : Richard, dept : Sales, salary :10000 ] Employee :[ Name : Rob, dept : Sales, salary :10000 ] Employee :[ Name : Michel, dept : Head Marketing, salary :20000 ] Employee :[ Name : Laura, dept : Marketing, salary :10000 ] Employee :[ Name : Bob, dept : Marketing, salary :10000 ]
裝飾器模式 (Decorator Pattern)
裝飾器模式允許在不改變其結構的情況下向現有物件新增新功能。這種設計模式屬於結構型模式,因為它充當現有類的包裝器。
此模式建立一個裝飾器類,該類包裝原始類並提供附加功能,同時保持類方法簽名不變。
我們將透過以下示例演示裝飾器模式的使用,在該示例中,我們將用某種顏色裝飾形狀而無需更改形狀類。
實現
我們將建立一個Shape介面和實現Shape介面的具體類。然後,我們建立一個抽象裝飾器類ShapeDecorator,它實現Shape介面並將其Shape物件作為其例項變數。
RedShapeDecorator是實現ShapeDecorator的具體類。
我們的演示類DecoratorPatternDemo將使用RedShapeDecorator來裝飾Shape物件。
步驟 1
建立一個介面。
Shape.java
public interface Shape {
void draw();
}
步驟 2
建立實現同一介面的具體類。
Rectangle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
Circle.java
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
步驟 3
建立實現Shape介面的抽象裝飾器類。
ShapeDecorator.java
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
步驟 4
建立擴充套件ShapeDecorator類的具體裝飾器類。
RedShapeDecorator.java
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
步驟 5
使用RedShapeDecorator裝飾Shape物件。
DecoratorPatternDemo.java
public class DecoratorPatternDemo {
public static void main(String[] args) {
Shape circle = new Circle();
Shape redCircle = new RedShapeDecorator(new Circle());
Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();
System.out.println("\nCircle of red border");
redCircle.draw();
System.out.println("\nRectangle of red border");
redRectangle.draw();
}
}
步驟 6
驗證輸出。
Circle with normal border Shape: Circle Circle of red border Shape: Circle Border Color: Red Rectangle of red border Shape: Rectangle Border Color: Red
外觀模式 (Facade Pattern)
外觀模式隱藏了系統的複雜性,並向客戶端提供了一個介面,客戶端可以使用該介面訪問系統。這種設計模式屬於結構型模式,因為它向現有系統添加了一個介面以隱藏其複雜性。
此模式涉及一個類,該類提供客戶端所需的簡化方法,並將呼叫委託給現有系統類的方 法。
實現
我們將建立一個Shape介面和實現Shape介面的具體類。下一步定義一個外觀類ShapeMaker。
ShapeMaker類使用具體類將使用者呼叫委託給這些類。我們的演示類FacadePatternDemo將使用ShapeMaker類顯示結果。
步驟 1
建立一個介面。
Shape.java
public interface Shape {
void draw();
}
步驟 2
建立實現同一介面的具體類。
Rectangle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle::draw()");
}
}
Square.java
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Square::draw()");
}
}
Circle.java
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
步驟 3
建立一個外觀類。
ShapeMaker.java
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;
public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}
public void drawCircle(){
circle.draw();
}
public void drawRectangle(){
rectangle.draw();
}
public void drawSquare(){
square.draw();
}
}
步驟 4
使用外觀繪製各種形狀。
FacadePatternDemo.java
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
}
步驟 5
驗證輸出。
Circle::draw() Rectangle::draw() Square::draw()
享元模式 (Flyweight Pattern)
享元模式主要用於減少建立的物件數量,以減少記憶體佔用並提高效能。這種設計模式屬於結構型模式,因為它提供減少物件數量從而改進應用程式所需物件結構的方法。
享元模式嘗試透過儲存已經存在的類似物件來重用它們,並在找不到匹配的物件時建立新物件。我們將透過繪製 20 個不同位置的圓來演示此模式,但我們只建立 5 個物件。只有 5 種顏色可用,因此顏色屬性用於檢查已經存在的Circle物件。
實現
我們將建立一個Shape介面和實現Shape介面的具體類Circle。下一步定義一個工廠類ShapeFactory。
ShapeFactory有一個Circle的HashMap,其鍵是Circle物件的顏色。每當請求建立特定顏色的圓到ShapeFactory時。ShapeFactory檢查其HashMap中的圓物件,如果找到Circle的物件,則返回該物件;否則,將建立一個新物件,將其儲存在hashmap中以供將來使用,並將其返回給客戶端。
我們的演示類FlyWeightPatternDemo將使用ShapeFactory獲取Shape物件。它將資訊(紅色/綠色/藍色/黑色/白色)傳遞給ShapeFactory以獲取其所需的所需顏色的圓。
步驟 1
建立一個介面。
Shape.java
public interface Shape {
void draw();
}
步驟 2
建立實現相同介面的具體類。
Circle.java
public class Circle implements Shape {
private String color;
private int x;
private int y;
private int radius;
public Circle(String color){
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setRadius(int radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Circle: Draw() [Color : " + color
+", x : " + x +", y :" + y +", radius :" + radius);
}
}
步驟 3
建立一個工廠,根據給定的資訊生成具體類的物件。
ShapeFactory.java
import java.util.HashMap;
public class ShapeFactory {
// Uncomment the compiler directive line and
// javac *.java will compile properly.
// @SuppressWarnings("unchecked")
private static final HashMap 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;
}
}
步驟 4
透過傳遞資訊(例如顏色)使用工廠獲取具體類的物件。
FlyweightPatternDemo.java
public class FlyweightPatternDemo {
private static final String colors[] =
{ "Red", "Green", "Blue", "White", "Black" };
public static void main(String[] args) {
for(int i=0; i < 20; ++i) {
Circle circle =
(Circle)ShapeFactory.getCircle(getRandomColor());
circle.setX(getRandomX());
circle.setY(getRandomY());
circle.setRadius(100);
circle.draw();
}
}
private static String getRandomColor() {
return colors[(int)(Math.random()*colors.length)];
}
private static int getRandomX() {
return (int)(Math.random()*100 );
}
private static int getRandomY() {
return (int)(Math.random()*100);
}
}
步驟 5
驗證輸出。
Creating circle of color : Black Circle: Draw() [Color : Black, x : 36, y :71, radius :100 Creating circle of color : Green Circle: Draw() [Color : Green, x : 27, y :27, radius :100 Creating circle of color : White Circle: Draw() [Color : White, x : 64, y :10, radius :100 Creating circle of color : Red Circle: Draw() [Color : Red, x : 15, y :44, radius :100 Circle: Draw() [Color : Green, x : 19, y :10, radius :100 Circle: Draw() [Color : Green, x : 94, y :32, radius :100 Circle: Draw() [Color : White, x : 69, y :98, radius :100 Creating circle of color : Blue Circle: Draw() [Color : Blue, x : 13, y :4, radius :100 Circle: Draw() [Color : Green, x : 21, y :21, radius :100 Circle: Draw() [Color : Blue, x : 55, y :86, radius :100 Circle: Draw() [Color : White, x : 90, y :70, radius :100 Circle: Draw() [Color : Green, x : 78, y :3, radius :100 Circle: Draw() [Color : Green, x : 64, y :89, radius :100 Circle: Draw() [Color : Blue, x : 3, y :91, radius :100 Circle: Draw() [Color : Blue, x : 62, y :82, radius :100 Circle: Draw() [Color : Green, x : 97, y :61, radius :100 Circle: Draw() [Color : Green, x : 86, y :12, radius :100 Circle: Draw() [Color : Green, x : 38, y :93, radius :100 Circle: Draw() [Color : Red, x : 76, y :82, radius :100 Circle: Draw() [Color : Blue, x : 95, y :82, radius :100
代理模式 (Proxy Pattern)
在代理模式中,一個類代表另一個類的功能。這種設計模式屬於結構型模式。
在代理模式中,我們建立一個包含原始物件的代理物件,以便將其功能與外部世界互動。
實現
我們將建立一個Image介面以及實現Image介面的具體類。ProxyImage是一個代理類,用於減少RealImage物件載入時的記憶體佔用。
ProxyPatternDemo,我們的演示類將使用ProxyImage來獲取Image物件,並在需要時載入和顯示。
步驟 1
建立一個介面。
Image.java
public interface Image {
void display();
}
步驟 2
建立實現同一介面的具體類。
RealImage.java
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName){
System.out.println("Loading " + fileName);
}
}
ProxyImage.java
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
}
步驟 3
根據需要使用ProxyImage獲取RealImage類的物件。
ProxyPatternDemo.java
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
//image will be loaded from disk
image.display();
System.out.println("");
//image will not be loaded from disk
image.display();
}
}
步驟 4
驗證輸出。
Loading test_10mb.jpg Displaying test_10mb.jpg Displaying test_10mb.jpg
責任鏈模式
顧名思義,責任鏈模式為請求建立了一個接收者物件的鏈。這種模式根據請求型別解耦了請求的發起者和接收者。這種模式屬於行為型模式。
在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個物件無法處理請求,則將其傳遞給下一個接收者,依此類推。
實現
我們建立了一個抽象類AbstractLogger,它具有日誌記錄級別。然後,我們建立了三種擴充套件AbstractLogger的日誌記錄器型別。每個日誌記錄器都會檢查訊息級別與其級別是否匹配,如果匹配則列印,否則不列印並將訊息傳遞給其下一個日誌記錄器。
步驟 1
建立一個抽象日誌記錄器類。
AbstractLogger.java
public abstract class AbstractLogger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
//next element in chain or responsibility
protected AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger){
this.nextLogger = nextLogger;
}
public void logMessage(int level, String message){
if(this.level <= level){
write(message);
}
if(nextLogger !=null){
nextLogger.logMessage(level, message);
}
}
abstract protected void write(String message);
}
步驟 2
建立擴充套件日誌記錄器的具體類。
ConsoleLogger.java
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Standard Console::Logger: " + message);
}
}
ErrorLogger.java
public class ErrorLogger extends AbstractLogger {
public ErrorLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Error Console::Logger: " + message);
}
}
FileLogger.java
public class FileLogger extends AbstractLogger {
public FileLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("File::Logger: " + message);
}
}
步驟 3
建立不同型別的日誌記錄器。為它們分配錯誤級別並在每個日誌記錄器中設定下一個日誌記錄器。每個日誌記錄器中的下一個日誌記錄器代表鏈的一部分。
ChainPatternDemo.java
public class ChainPatternDemo {
private static AbstractLogger getChainOfLoggers(){
AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
errorLogger.setNextLogger(fileLogger);
fileLogger.setNextLogger(consoleLogger);
return errorLogger;
}
public static void main(String[] args) {
AbstractLogger loggerChain = getChainOfLoggers();
loggerChain.logMessage(AbstractLogger.INFO,
"This is an information.");
loggerChain.logMessage(AbstractLogger.DEBUG,
"This is an debug level information.");
loggerChain.logMessage(AbstractLogger.ERROR,
"This is an error information.");
}
}
步驟 4
驗證輸出。
Standard Console::Logger: This is an information. File::Logger: This is an debug level information. Standard Console::Logger: This is an debug level information. Error Console::Logger: This is an error information. File::Logger: This is an error information. Standard Console::Logger: This is an error information.
命令模式
命令模式是一種資料驅動型設計模式,屬於行為型模式類別。請求被封裝在一個物件中作為命令,並傳遞給呼叫者物件。呼叫者物件查詢可以處理此命令的適當物件,並將命令傳遞給相應的物件,該物件執行命令。
實現
我們建立了一個Order介面,它充當命令。我們建立了一個Stock類,它充當請求。我們建立了實現Order介面的具體命令類BuyStock和SellStock,它們將執行實際的命令處理。建立了一個Broker類,它充當呼叫者物件。它可以接受訂單並下訂單。
Broker物件使用命令模式來識別哪個物件將根據命令型別執行哪個命令。CommandPatternDemo,我們的演示類將使用Broker類來演示命令模式。
步驟 1
建立一個命令介面。
Order.java
public interface Order {
void execute();
}
步驟 2
建立一個請求類。
Stock.java
public class Stock {
private String name = "ABC";
private int quantity = 10;
public void buy(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] bought");
}
public void sell(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] sold");
}
}
步驟 3
建立實現Order介面的具體類。
BuyStock.java
public class BuyStock implements Order {
private Stock abcStock;
public BuyStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.buy();
}
}
SellStock.java
public class SellStock implements Order {
private Stock abcStock;
public SellStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.sell();
}
}
步驟 4
建立命令呼叫者類。
Broker.java
import java.util.ArrayList;
import java.util.List;
public class Broker {
private List<Order> orderList = new ArrayList<Order>();
public void takeOrder(Order order){
orderList.add(order);
}
public void placeOrders(){
for (Order order : orderList) {
order.execute();
}
orderList.clear();
}
}
步驟 5
使用Broker類來接收和執行命令。
CommandPatternDemo.java
public class CommandPatternDemo {
public static void main(String[] args) {
Stock abcStock = new Stock();
BuyStock buyStockOrder = new BuyStock(abcStock);
SellStock sellStockOrder = new SellStock(abcStock);
Broker broker = new Broker();
broker.takeOrder(buyStockOrder);
broker.takeOrder(sellStockOrder);
broker.placeOrders();
}
}
步驟 6
驗證輸出。
Stock [ Name: ABC, Quantity: 10 ] bought Stock [ Name: ABC, Quantity: 10 ] sold
直譯器模式
直譯器模式提供了一種評估語言語法或表示式的途徑。這種模式屬於行為型模式。這種模式涉及實現一個表示式介面,該介面指示解釋特定上下文。這種模式用於SQL解析、符號處理引擎等。
實現
我們將建立一個Expression介面以及實現Expression介面的具體類。定義了一個TerminalExpression類,它充當所討論上下文的直譯器。其他類OrExpression、AndExpression用於建立組合表示式。
InterpreterPatternDemo,我們的演示類將使用Expression類來建立規則並演示表示式的解析。
步驟 1
建立一個表示式介面。
Expression.java
public interface Expression {
public boolean interpret(String context);
}
步驟 2
建立實現上述介面的具體類。
TerminalExpression.java
public class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data){
this.data = data;
}
@Override
public boolean interpret(String context) {
if(context.contains(data)){
return true;
}
return false;
}
}
OrExpression.java
public class OrExpression implements Expression {
private Expression expr1 = null;
private Expression expr2 = null;
public OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
AndExpression.java
public class AndExpression implements Expression {
private Expression expr1 = null;
private Expression expr2 = null;
public AndExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) && expr2.interpret(context);
}
}
步驟 3
InterpreterPatternDemo使用Expression類建立規則,然後解析它們。
InterpreterPatternDemo.java
public class InterpreterPatternDemo {
//Rule: Robert and John are male
public static Expression getMaleExpression(){
Expression robert = new TerminalExpression("Robert");
Expression john = new TerminalExpression("John");
return new OrExpression(robert, john);
}
//Rule: Julie is a married women
public static Expression getMarriedWomanExpression(){
Expression julie = new TerminalExpression("Julie");
Expression married = new TerminalExpression("Married");
return new AndExpression(julie, married);
}
public static void main(String[] args) {
Expression isMale = getMaleExpression();
Expression isMarriedWoman = getMarriedWomanExpression();
System.out.println("John is male? " + isMale.interpret("John"));
System.out.println("Julie is a married women? "
+ isMarriedWoman.interpret("Married Julie"));
}
}
步驟 4
驗證輸出。
John is male? true Julie is a married women? true
迭代器模式
迭代器模式在Java和.Net程式設計環境中非常常用。這種模式用於以順序方式訪問集合物件的元素,而無需瞭解其底層表示。
迭代器模式屬於行為型模式類別。
實現
我們將建立一個Iterator介面,它描述導航方法,以及一個Container介面,它返回迭代器。實現Container介面的具體類將負責實現Iterator介面並使用它。
IteratorPatternDemo,我們的演示類將使用NamesRepository(一個具體的類實現)來列印儲存在NamesRepository中的集合Names。
步驟 1
建立介面。
Iterator.java
public interface Iterator {
public boolean hasNext();
public Object next();
}
Container.java
public interface Container {
public Iterator getIterator();
}
步驟 2
建立實現Container介面的具體類。此類具有內部類NameIterator,它實現了Iterator介面。
NameRepository.java
public class NameRepository implements Container {
public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};
@Override
public Iterator getIterator() {
return new NameIterator();
}
private class NameIterator implements Iterator {
int index;
@Override
public boolean hasNext() {
if(index < names.length){
return true;
}
return false;
}
@Override
public Object next() {
if(this.hasNext()){
return names[index++];
}
return null;
}
}
}
步驟 3
使用NameRepository獲取迭代器並列印名稱。
IteratorPatternDemo.java
public class IteratorPatternDemo {
public static void main(String[] args) {
NameRepository namesRepository = new NameRepository();
for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){
String name = (String)iter.next();
System.out.println("Name : " + name);
}
}
}
步驟 4
驗證輸出。
Name : Robert Name : John Name : Julie Name : Lora
中介者模式
中介者模式用於減少多個物件或類之間的通訊複雜性。這種模式提供了一箇中介者類,該類通常處理不同類之間的所有通訊,並通過鬆耦合支援程式碼的易維護性。中介者模式屬於行為型模式類別。
實現
我們透過聊天室的示例演示中介者模式,在聊天室中,多個使用者可以向聊天室傳送訊息,而聊天室負責向所有使用者顯示訊息。我們建立了兩個類ChatRoom和User。User物件將使用ChatRoom方法共享其訊息。
MediatorPatternDemo,我們的演示類將使用User物件來顯示它們之間的通訊。
步驟 1
建立中介者類。
ChatRoom.java
import java.util.Date;
public class ChatRoom {
public static void showMessage(User user, String message){
System.out.println(new Date().toString()
+ " [" + user.getName() +"] : " + message);
}
}
步驟 2
建立使用者類
User.java
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name){
this.name = name;
}
public void sendMessage(String message){
ChatRoom.showMessage(this,message);
}
}
步驟 3
使用User物件來顯示它們之間的通訊。
MediatorPatternDemo.java
public class MediatorPatternDemo {
public static void main(String[] args) {
User robert = new User("Robert");
User john = new User("John");
robert.sendMessage("Hi! John!");
john.sendMessage("Hello! Robert!");
}
}
步驟 4
驗證輸出。
Thu Jan 31 16:05:46 IST 2013 [Robert] : Hi! John! Thu Jan 31 16:05:46 IST 2013 [John] : Hello! Robert!
備忘錄模式
備忘錄模式用於在我們需要將物件的狀態還原到之前的狀態時使用。備忘錄模式屬於行為型模式類別。
實現
備忘錄模式使用三個參與者類。備忘錄包含要還原的物件的狀態。發起者建立並將狀態儲存在備忘錄物件中,而管理者物件負責從備忘錄中還原物件狀態。我們建立了Memento、Originator和CareTaker類。
MementoPatternDemo,我們的演示類將使用CareTaker和Originator物件來顯示物件狀態的還原。
步驟 1
建立備忘錄類。
Memento.java
public class Memento {
private String state;
public Memento(String state){
this.state = state;
}
public String getState(){
return state;
}
}
步驟 2
建立發起者類
Originator.java
public class Originator {
private String state;
public void setState(String state){
this.state = state;
}
public String getState(){
return state;
}
public Memento saveStateToMemento(){
return new Memento(state);
}
public void getStateFromMemento(Memento Memento){
state = memento.getState();
}
}
步驟 3
建立管理者類
CareTaker.java
import java.util.ArrayList;
import java.util.List;
public class CareTaker {
private List<Memento> mementoList = new ArrayList<Memento>();
public void add(Memento state){
mementoList.add(state);
}
public Memento get(int index){
return mementoList.get(index);
}
}
步驟 4
使用CareTaker和Originator物件。
MementoPatternDemo.java
public class MementoPatternDemo {
public static void main(String[] args) {
Originator originator = new Originator();
CareTaker careTaker = new CareTaker();
originator.setState("State #1");
originator.setState("State #2");
careTaker.add(originator.saveStateToMemento());
originator.setState("State #3");
careTaker.add(originator.saveStateToMemento());
originator.setState("State #4");
System.out.println("Current State: " + originator.getState());
originator.getStateFromMemento(careTaker.get(0));
System.out.println("First saved State: " + originator.getState());
originator.getStateFromMemento(careTaker.get(1));
System.out.println("Second saved State: " + originator.getState());
}
}
步驟 5
驗證輸出。
Current State: State #4 First saved State: State #2 Second saved State: State #3
觀察者模式
當物件之間存在一對多關係時,例如,如果修改一個物件,則需要自動通知其依賴物件,則使用觀察者模式。觀察者模式屬於行為型模式類別。
實現
觀察者模式使用三個參與者類:主題、觀察者和客戶端。主題,一個具有附加和分離觀察者到客戶端物件的方法的物件。我們建立了Subject類、Observer抽象類以及擴充套件Observer抽象類的具體類。
ObserverPatternDemo,我們的演示類將使用Subject和具體類物件來演示觀察者模式。
步驟 1
建立主題類。
Subject.java
import java.util.ArrayList;
import java.util.List;
public class Subject {
private List<Observer> observers
= new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void attach(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
步驟 2
建立觀察者類。
Observer.java
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
步驟 3
建立具體的觀察者類
BinaryObserver.java
public class BinaryObserver extends Observer{
public BinaryObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Binary String: "
+ Integer.toBinaryString( subject.getState() ) );
}
}
OctalObserver.java
public class OctalObserver extends Observer{
public OctalObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Octal String: "
+ Integer.toOctalString( subject.getState() ) );
}
}
HexaObserver.java
public class HexaObserver extends Observer{
public HexaObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Hex String: "
+ Integer.toHexString( subject.getState() ).toUpperCase() );
}
}
步驟 4
使用Subject和具體的觀察者物件。
ObserverPatternDemo.java
public class ObserverPatternDemo {
public static void main(String[] args) {
Subject subject = new Subject();
new HexaObserver(subject);
new OctalObserver(subject);
new BinaryObserver(subject);
System.out.println("First state change: 15");
subject.setState(15);
System.out.println("Second state change: 10");
subject.setState(10);
}
}
步驟 5
驗證輸出。
First state change: 15 Hex String: F Octal String: 17 Binary String: 1111 Second state change: 10 Hex String: A Octal String: 12 Binary String: 1010
狀態模式
在狀態模式中,類的行為根據其狀態而改變。這種設計模式屬於行為模式。
在狀態模式中,我們建立表示各種狀態的物件以及一個上下文物件,其行為隨著其狀態物件的改變而改變。
實現
我們將建立一個State介面,定義一個操作以及實現State介面的具體狀態類。Context是一個包含狀態的類。
StaePatternDemo,我們的演示類將使用Context和狀態物件來演示基於其所處的狀態型別而改變的上下文行為。
步驟 1
建立一個介面。
Image.java
public interface State {
public void doAction(Context context);
}
步驟 2
建立實現同一介面的具體類。
StartState.java
public class StartState implements State {
public void doAction(Context context) {
System.out.println("Player is in start state");
context.setState(this);
}
public String toString(){
return "Start State";
}
}
StopState.java
public class StopState implements State {
public void doAction(Context context) {
System.out.println("Player is in stop state");
context.setState(this);
}
public String toString(){
return "Stop State";
}
}
步驟 3
建立Context類。
Context.java
public class Context {
private State state;
public Context(){
state = null;
}
public void setState(State state){
this.state = state;
}
public State getState(){
return state;
}
}
步驟 4
使用Context檢視當State改變時行為的變化。
StatePatternDemo.java
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.doAction(context);
System.out.println(context.getState().toString());
StopState stopState = new StopState();
stopState.doAction(context);
System.out.println(context.getState().toString());
}
}
步驟 5
驗證輸出。
Player is in start state Start State Player is in stop state Stop State
空物件模式
在空物件模式中,空物件替換了對NULL物件例項的檢查。我們無需對null值進行if檢查,空物件反映了不執行任何操作的關係。這種空物件也可用於在資料不可用時提供預設行為。
在空物件模式中,我們建立一個抽象類,指定要執行的各種操作,具體類擴充套件此類,以及一個空物件類,提供此類的什麼也不做的實現,並在我們需要檢查null值的地方無縫使用。
實現
我們將建立一個AbstractCustomer抽象類,定義客戶的名稱以及擴充套件AbstractCustomer類的具體類。建立了一個工廠類CustomerFactory,根據傳遞給它的客戶名稱返回RealCustomer或NullCustomer物件。
NullPatternDemo,我們的演示類將使用CustomerFactory來演示空物件模式的使用。
步驟 1
建立一個抽象類。
AbstractCustomer.java
public abstract class AbstractCustomer {
protected String name;
public abstract boolean isNil();
public abstract String getName();
}
步驟 2
建立擴充套件上述類的具體類。
RealCustomer.java
public class RealCustomer extends AbstractCustomer {
public RealCustomer(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public boolean isNil() {
return false;
}
}
NullCustomer.java
public class NullCustomer extends AbstractCustomer {
@Override
public String getName() {
return "Not Available in Customer Database";
}
@Override
public boolean isNil() {
return true;
}
}
步驟 3
建立CustomerFactory類。
CustomerFactory.java
public class CustomerFactory {
public static final String[] names = {"Rob", "Joe", "Julie"};
public static AbstractCustomer getCustomer(String name){
for (int i = 0; i < names.length; i++) {
if (names[i].equalsIgnoreCase(name)){
return new RealCustomer(name);
}
}
return new NullCustomer();
}
}
步驟 4
使用CustomerFactory根據傳遞給它的客戶名稱獲取RealCustomer或NullCustomer物件。
NullPatternDemo.java
public class NullPatternDemo {
public static void main(String[] args) {
AbstractCustomer customer1 = CustomerFactory.getCustomer("Rob");
AbstractCustomer customer2 = CustomerFactory.getCustomer("Bob");
AbstractCustomer customer3 = CustomerFactory.getCustomer("Julie");
AbstractCustomer customer4 = CustomerFactory.getCustomer("Laura");
System.out.println("Customers");
System.out.println(customer1.getName());
System.out.println(customer2.getName());
System.out.println(customer3.getName());
System.out.println(customer4.getName());
}
}
步驟 5
驗證輸出。
Customers Rob Not Available in Customer Database Julie Not Available in Customer Database
策略模式
在策略模式中,可以在執行時更改類的行為或其演算法。這種設計模式屬於行為模式。
在策略模式中,我們建立表示各種策略的物件以及一個上下文物件,其行為根據其策略物件而變化。策略物件更改上下文物件的執行演算法。
實現
我們將建立一個Strategy介面,定義一個動作以及實現Strategy介面的具體策略類。Context是一個使用策略的類。
StrategyPatternDemo,我們的演示類將使用Context和策略物件來演示基於其部署或使用的策略的Context行為變化。
步驟 1
建立一個介面。
Strategy.java
public interface Strategy {
public int doOperation(int num1, int num2);
}
步驟 2
建立實現同一介面的具體類。
OperationAdd.java
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
OperationSubstract.java
public class OperationSubstract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
OperationMultiply.java
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
步驟 3
建立Context類。
Context.java
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
步驟 4
使用Context檢視其更改Strategy時行為的變化。
StatePatternDemo.java
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubstract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
步驟 5
驗證輸出。
10 + 5 = 15 10 - 5 = 5 10 * 5 = 50
模板模式(Template Pattern)
在模板模式中,抽象類公開定義的方法/模板來執行其方法。它的子類可以根據需要覆蓋方法實現,但呼叫方式必須與抽象類定義的方式相同。此模式屬於行為模式類別。
實現
我們將建立一個Game抽象類,定義帶有模板方法的操作,該模板方法設定為final,因此無法被覆蓋。Cricket和Football是擴充套件Game並覆蓋其方法的具體類。
TemplatePatternDemo,我們的演示類將使用Game來演示模板模式的使用。
步驟 1
建立一個帶有最終模板方法的抽象類。
Game.java
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//template method
public final void play(){
//initialize the game
initialize();
//start game
startPlay();
//end game
endPlay();
}
}
步驟 2
建立擴充套件上述類的具體類。
Cricket.java
public class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
Football.java
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
步驟 3
使用Game的模板方法play()來演示定義的遊戲玩法。
TemplatePatternDemo.java
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
步驟 4
驗證輸出。
Cricket Game Initialized! Start playing. Cricket Game Started. Enjoy the game! Cricket Game Finished! Football Game Initialized! Start playing. Football Game Started. Enjoy the game! Football Game Finished!
訪問者模式(Visitor Pattern)
在訪問者模式中,我們使用一個訪問者類來改變元素類的執行演算法。透過這種方式,元素的執行演算法可以隨著訪問者的變化而變化。此模式屬於行為模式類別。根據該模式,元素物件必須接受訪問者物件,以便訪問者物件處理元素物件的操作。
實現
我們將建立一個ComputerPart介面,定義accept操作。Keyboard、Mouse、Monitor和Computer是實現ComputerPart介面的具體類。我們將定義另一個介面ComputerPartVisitor,它將定義訪問者類的操作。Computer使用具體的訪問者來執行相應的操作。
VisitorPatternDemo,我們的演示類將使用Computer和ComputerPartVisitor類來演示訪問者模式的使用。
步驟 1
定義一個介面來表示元素。
ComputerPart.java
public interface class ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}
步驟 2
建立擴充套件上述類的具體類。
Keyboard.java
public class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
Monitor.java
public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
Mouse.java
public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
Computer.java
public class Computer implements ComputerPart {
ComputerPart[] parts;
public Computer(){
parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
步驟 3
定義一個介面來表示訪問者。
ComputerPartVisitor.java
public interface ComputerPartVisitor {
public void visit(Computer computer);
public void visit(Mouse mouse);
public void visit(Keyboard keyboard);
public void visit(Monitor monitor);
}
步驟 4
建立實現上述類的具體訪問者。
ComputerPartDisplayVisitor.java
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
步驟 5
使用ComputerPartDisplayVisitor來顯示Computer的部件。
VisitorPatternDemo.java
public class VisitorPatternDemo {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}
步驟 6
驗證輸出。
Displaying Mouse. Displaying Keyboard. Displaying Monitor. Displaying Computer.
MVC模式
MVC模式代表模型-檢視-控制器模式。此模式用於分離應用程式的關注點。
模型(Model) - 模型表示承載資料的物件或JAVA POJO。如果其資料發生更改,它還可以具有更新控制器的邏輯。
檢視(View) - 視圖表示模型包含資料的視覺化。
控制器(Controller) - 控制器同時作用於模型和檢視。它控制資料流入模型物件,並在資料更改時更新檢視。它使檢視和模型保持分離。
實現
我們將建立一個充當模型的Student物件。StudentView將是一個可以在控制檯上列印學生詳細資訊的檢視類,而StudentController是負責將資料儲存在Student物件中並相應地更新檢視StudentView的控制器類。
MVCPatternDemo,我們的演示類將使用StudentController來演示MVC模式的使用。
步驟 1
建立模型。
Student.java
public class Student {
private String rollNo;
private String name;
public String getRollNo() {
return rollNo;
}
public void setRollNo(String rollNo) {
this.rollNo = rollNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
步驟 2
建立檢視。
StudentView.java
public class StudentView {
public void printStudentDetails(String studentName, String studentRollNo){
System.out.println("Student: ");
System.out.println("Name: " + studentName);
System.out.println("Roll No: " + studentRollNo);
}
}
步驟 3
建立控制器。
StudentController.java
public class StudentController {
private Student model;
private StudentView view;
public StudentController(Student model, StudentView view){
this.model = model;
this.view = view;
}
public void setStudentName(String name){
model.setName(name);
}
public String getStudentName(){
return model.getName();
}
public void setStudentRollNo(String rollNo){
model.setRollNo(rollNo);
}
public String getStudentRollNo(){
return model.getRollNo();
}
public void updateView(){
view.printStudentDetails(model.getName(), model.getRollNo());
}
}
步驟 4
使用StudentController方法來演示MVC設計模式的使用。
MVCPatternDemo.java
public class MVCPatternDemo {
public static void main(String[] args) {
//fetch student record based on his roll no from the database
Student model = retriveStudentFromDatabase();
//Create a view : to write student details on console
StudentView view = new StudentView();
StudentController controller = new StudentController(model, view);
controller.updateView();
//update model data
controller.setStudentName("John");
controller.updateView();
}
private static Student retriveStudentFromDatabase(){
Student student = new Student();
student.setName("Robert");
student.setRollNo("10");
return student;
}
}
步驟 5
驗證輸出。
Student: Name: Robert Roll No: 10 Student: Name: Julie Roll No: 10
業務代表模式
業務委託模式用於解耦表示層和業務層。它基本上用於減少表示層程式碼中對業務層程式碼的通訊或遠端查詢功能。在業務層中,我們有以下實體。
客戶端(Client) - 表示層程式碼可以是JSP、servlet或UI Java程式碼。
業務委託(Business Delegate) - 客戶端實體訪問業務服務方法的單一入口點類。
查詢服務(LookUp Service) - 查詢服務物件負責獲取相關的業務實現,並向業務委託物件提供業務物件訪問。
業務服務(Business Service) - 業務服務介面。具體類實現此業務服務以提供實際的業務實現邏輯。
實現
我們將建立一個Client、BusinessDelegate、BusinessService、LookUpService、JMSService和EJBService,分別代表業務委託模式的各種實體。
BusinessDelegatePatternDemo,我們的演示類將使用BusinessDelegate和Client來演示業務委託模式的使用。
步驟 1
建立BusinessService介面。
BusinessService.java
public interface BusinessService {
public void doProcessing();
}
步驟 2
建立具體服務類。
EJBService.java
public class EJBService implements BusinessService {
@Override
public void doProcessing() {
System.out.println("Processing task by invoking EJB Service");
}
}
JMSService.java
public class JMSService implements BusinessService {
@Override
public void doProcessing() {
System.out.println("Processing task by invoking JMS Service");
}
}
步驟 3
建立業務查詢服務。
BusinessLookUp.java
public class BusinessLookUp {
public BusinessService getBusinessService(String serviceType){
if(serviceType.equalsIgnoreCase("EJB")){
return new EJBService();
}else {
return new JMSService();
}
}
}
步驟 4
建立業務委託。
BusinessLookUp.java
public class BusinessDelegate {
private BusinessLookUp lookupService = new BusinessLookUp();
private BusinessService businessService;
private String serviceType;
public void setServiceType(String serviceType){
this.serviceType = serviceType;
}
public void doTask(){
businessService = lookupService.getBusinessService(serviceType);
businessService.doProcessing();
}
}
步驟 5
建立客戶端。
Student.java
public class Client {
BusinessDelegate businessService;
public Client(BusinessDelegate businessService){
this.businessService = businessService;
}
public void doTask(){
businessService.doTask();
}
}
步驟 6
使用BusinessDelegate和Client類來演示業務委託模式。
BusinessDelegatePatternDemo.java
public class BusinessDelegatePatternDemo {
public static void main(String[] args) {
BusinessDelegate businessDelegate = new BusinessDelegate();
businessDelegate.setServiceType("EJB");
Client client = new Client(businessDelegate);
client.doTask();
businessDelegate.setServiceType("JMS");
client.doTask();
}
}
步驟 7
驗證輸出。
Processing task by invoking EJB Service Processing task by invoking JMS Service
組合實體模式
組合實體模式用於EJB持久化機制。組合實體是一個EJB實體bean,它表示物件的圖形。當更新組合實體時,內部依賴的物件bean會自動更新,因為它們由EJB實體bean管理。組合實體bean中的參與者如下。
組合實體(Composite Entity) - 它是主要的實體bean。它可以是粗粒度的,也可以包含粗粒度的物件以用於持久化目的。
粗粒度物件(Coarse-Grained Object) - 此物件包含依賴物件。它有自己的生命週期,也管理依賴物件的生命週期。
依賴物件(Dependent Object) - 依賴物件是一個依賴於粗粒度物件持久化生命週期的物件。
策略(Strategies) - 策略表示如何實現組合實體。
實現
我們將建立一個充當組合實體的CompositeEntity物件。CoarseGrainedObject將是一個包含依賴物件的類。CompositeEntityPatternDemo,我們的演示類將使用Client類來演示組合實體模式的使用。
步驟 1
建立依賴物件。
DependentObject1.java
public class DependentObject1 {
private String data;
public void setData(String data){
this.data = data;
}
public String getData(){
return data;
}
}
DependentObject2.java
public class DependentObject2 {
private String data;
public void setData(String data){
this.data = data;
}
public String getData(){
return data;
}
}
步驟 2
建立粗粒度物件。
CoarseGrainedObject.java
public class CoarseGrainedObject {
DependentObject1 do1 = new DependentObject1();
DependentObject2 do2 = new DependentObject2();
public void setData(String data1, String data2){
do1.setData(data1);
do2.setData(data2);
}
public String[] getData(){
return new String[] {do1.getData(),do2.getData()};
}
}
步驟 3
建立組合實體。
CompositeEntity.java
public class CompositeEntity {
private CoarseGrainedObject cgo = new CoarseGrainedObject();
public void setData(String data1, String data2){
cgo.setData(data1, data2);
}
public String[] getData(){
return cgo.getData();
}
}
步驟 4
建立使用組合實體的客戶端類。
Client.java
public class Client {
private CompositeEntity compositeEntity = new CompositeEntity();
public void printData(){
for (int i = 0; i < compositeEntity.getData().length; i++) {
System.out.println("Data: " + compositeEntity.getData()[i]);
}
}
public void setData(String data1, String data2){
compositeEntity.setData(data1, data2);
}
}
步驟 5
使用Client來演示組合實體設計模式的使用。
CompositeEntityPatternDemo.java
public class CompositeEntityPatternDemo {
public static void main(String[] args) {
Client client = new Client();
client.setData("Test", "Data");
client.printData();
client.setData("Second Test", "Data1");
client.printData();
}
}
步驟 6
驗證輸出。
Data: Test Data: Data Data: Second Test Data: Data1
資料訪問物件模式
資料訪問物件模式或DAO模式用於將低階資料訪問API或操作與高階業務服務分離。資料訪問物件模式中的參與者如下。
資料訪問物件介面(Data Access Object Interface) - 此介面定義要在模型物件上執行的標準操作。
資料訪問物件具體類(Data Access Object concrete class) - 此類實現上述介面。此類負責從資料來源(可以是資料庫/xml或任何其他儲存機制)獲取資料。
模型物件或值物件(Model Object or Value Object) - 此物件是簡單的POJO,包含get/set方法以儲存使用DAO類檢索的資料。
實現
我們將建立一個充當模型或值物件的Student物件。StudentDao是資料訪問物件介面。StudentDaoImpl是實現資料訪問物件介面的具體類。DaoPatternDemo,我們的演示類將使用StudentDao來演示資料訪問物件模式的使用。
步驟 1
建立值物件。
Student.java
public class Student {
private String name;
private int rollNo;
Student(String name, int rollNo){
this.name = name;
this.rollNo = rollNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRollNo() {
return rollNo;
}
public void setRollNo(int rollNo) {
this.rollNo = rollNo;
}
}
步驟 2
建立資料訪問物件介面。
StudentDao.java
import java.util.List;
public interface StudentDao {
public List<Student> getAllStudents();
public Student getStudent(int rollNo);
public void updateStudent(Student student);
public void deleteStudent(Student student);
}
步驟 3
建立實現上述介面的具體類。
StudentDaoImpl.java
import java.util.ArrayList;
import java.util.List;
public class StudentDaoImpl implements StudentDao {
//list is working as a database
List<Student> students;
public StudentDaoImpl(){
students = new ArrayList<Student>();
Student student1 = new Student("Robert",0);
Student student2 = new Student("John",1);
students.add(student1);
students.add(student2);
}
@Override
public void deleteStudent(Student student) {
students.remove(student.getRollNo());
System.out.println("Student: Roll No " + student.getRollNo()
+", deleted from database");
}
//retrive list of students from the database
@Override
public List<Student> getAllStudents() {
return students;
}
@Override
public Student getStudent(int rollNo) {
return students.get(rollNo);
}
@Override
public void updateStudent(Student student) {
students.get(student.getRollNo()).setName(student.getName());
System.out.println("Student: Roll No " + student.getRollNo()
+", updated in the database");
}
}
步驟 4
使用StudentDao來演示資料訪問物件模式的使用。
CompositeEntityPatternDemo.java
public class DaoPatternDemo {
public static void main(String[] args) {
StudentDao studentDao = new StudentDaoImpl();
//print all students
for (Student student : studentDao.getAllStudents()) {
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
//update student
Student student =studentDao.getAllStudents().get(0);
student.setName("Michael");
studentDao.updateStudent(student);
//get the student
studentDao.getStudent(0);
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
}
步驟 5
驗證輸出。
Student: [RollNo : 0, Name : Robert ] Student: [RollNo : 1, Name : John ] Student: Roll No 0, updated in the database Student: [RollNo : 0, Name : Michael ]
前端控制器模式
前端控制器設計模式用於提供集中式請求處理機制,以便所有請求都由單個處理程式處理。此處理程式可以執行請求的身份驗證/授權/日誌記錄或跟蹤,然後將請求傳遞給相應的處理程式。此類設計模式的實體如下。
前端控制器(Front Controller) - 應用程式(基於Web/基於桌面)的所有請求的單個處理程式。
排程器(Dispatcher) - 前端控制器可以使用排程器物件,該物件可以將請求排程到相應的特定處理程式。
檢視(View) - 檢視是發出請求的物件。
實現
我們將建立一個FrontController和Dispatcher,分別充當前端控制器和排程器。HomeView和StudentView表示可以向前端控制器發出請求的各種檢視。
FrontControllerPatternDemo,我們的演示類將使用FrontController來演示前端控制器設計模式。
步驟 1
建立檢視。
HomeView.java
public class HomeView {
public void show(){
System.out.println("Displaying Home Page");
}
}
StudentView.java
public class StudentView {
public void show(){
System.out.println("Displaying Student Page");
}
}
步驟 2
建立排程器。
Dispatcher.java
public class Dispatcher {
private StudentView studentView;
private HomeView homeView;
public Dispatcher(){
studentView = new StudentView();
homeView = new HomeView();
}
public void dispatch(String request){
if(request.equalsIgnoreCase("STUDENT")){
studentView.show();
}else{
homeView.show();
}
}
}
步驟 3
建立FrontController
Context.java
public class FrontController {
private Dispatcher dispatcher;
public FrontController(){
dispatcher = new Dispatcher();
}
private boolean isAuthenticUser(){
System.out.println("User is authenticated successfully.");
return true;
}
private void trackRequest(String request){
System.out.println("Page requested: " + request);
}
public void dispatchRequest(String request){
//log each request
trackRequest(request);
//authenticate the user
if(isAuthenticUser()){
dispatcher.dispatch(request);
}
}
}
步驟 4
使用FrontController來演示前端控制器設計模式。
FrontControllerPatternDemo.java
public class FrontControllerPatternDemo {
public static void main(String[] args) {
FrontController frontController = new FrontController();
frontController.dispatchRequest("HOME");
frontController.dispatchRequest("STUDENT");
}
}
步驟 5
驗證輸出。
Page requested: HOME User is authenticated successfully. Displaying Home Page Page requested: STUDENT User is authenticated successfully. Displaying Student Page
攔截過濾器模式
攔截過濾器設計模式用於在希望對應用程式的請求或響應進行一些預處理/後處理時使用。在將請求傳遞給實際的目標應用程式之前,會定義過濾器並將其應用於請求。過濾器可以執行請求的身份驗證/授權/日誌記錄或跟蹤,然後將請求傳遞給相應的處理程式。此類設計模式的實體如下。
過濾器(Filter) - 執行請求處理程式請求執行之前或之後某些任務的過濾器。
過濾器鏈(Filter Chain) - 過濾器鏈包含多個過濾器,並幫助按定義的順序在目標上執行它們。
目標(Target) - 目標物件是請求處理程式
過濾器管理器(Filter Manager) - 過濾器管理器管理過濾器和過濾器鏈。
客戶端(Client) - 客戶端是向目標物件傳送請求的物件。
實現
我們將建立一個FilterChain、FilterManager、Target、Client作為代表我們實體的各種物件。AuthenticationFilter和DebugFilter表示具體的過濾器。
InterceptingFilterDemo,我們的演示類將使用Client來演示攔截過濾器設計模式。
步驟 1
建立過濾器介面。
Filter.java
public interface Filter {
public void execute(String request);
}
步驟 2
建立具體過濾器。
AuthenticationFilter.java
public class AuthenticationFilter implements Filter {
public void execute(String request){
System.out.println("Authenticating request: " + request);
}
}
DebugFilter.java
public class DebugFilter implements Filter {
public void execute(String request){
System.out.println("request log: " + request);
}
}
步驟 3
建立目標
Target.java
public class Target {
public void execute(String request){
System.out.println("Executing request: " + request);
}
}
步驟 4
建立過濾器鏈
FilterChain.java
import java.util.ArrayList;
import java.util.List;
public class FilterChain {
private List<Filter> filters = new ArrayList<Filter>();
private Target target;
public void addFilter(Filter filter){
filters.add(filter);
}
public void execute(String request){
for (Filter filter : filters) {
filter.execute(request);
}
target.execute(request);
}
public void setTarget(Target target){
this.target = target;
}
}
步驟 5
建立過濾器管理器
FilterManager.java
public class FilterManager {
FilterChain filterChain;
public FilterManager(Target target){
filterChain = new FilterChain();
filterChain.setTarget(target);
}
public void setFilter(Filter filter){
filterChain.addFilter(filter);
}
public void filterRequest(String request){
filterChain.execute(request);
}
}
步驟 6
建立客戶端
Client.java
public class Client {
FilterManager filterManager;
public void setFilterManager(FilterManager filterManager){
this.filterManager = filterManager;
}
public void sendRequest(String request){
filterManager.filterRequest(request);
}
}
步驟 7
使用客戶端演示攔截過濾器設計模式。
FrontControllerPatternDemo.java
public class InterceptingFilterDemo {
public static void main(String[] args) {
FilterManager filterManager = new FilterManager(new Target());
filterManager.setFilter(new AuthenticationFilter());
filterManager.setFilter(new DebugFilter());
Client client = new Client();
client.setFilterManager(filterManager);
client.sendRequest("HOME");
}
}
步驟 8
驗證輸出。
Authenticating request: HOME request log: HOME Executing request: HOME
服務定位器模式
當我們想要使用 JNDI 查詢定位各種服務時,可以使用服務定位器設計模式。考慮到查詢 JNDI 服務的成本較高,服務定位器模式利用快取技術。第一次需要服務時,服務定位器會在 JNDI 中查詢並快取服務物件。透過服務定位器進一步查詢相同服務會在其快取中進行,這在很大程度上提高了應用程式的效能。以下是這種設計模式的實體。
服務 - 將處理請求的實際服務。此類服務的引用需要在 JNDI 伺服器中查詢。
上下文/初始上下文 - JNDI 上下文,包含用於查詢目的的服務引用。
服務定位器 - 服務定位器是透過 JNDI 查詢獲取服務的單點聯絡,它會快取服務。
快取 - 用於儲存服務引用的快取,以便重用它們。
客戶端 - 客戶端是透過 ServiceLocator 呼叫服務的物件。
實現
我們將建立ServiceLocator、InitialContext、Cache、Service作為代表我們實體的各種物件。Service1 和 Service2 代表具體的服務。
我們的演示類ServiceLocatorPatternDemo在這裡充當客戶端,並將使用ServiceLocator來演示服務定位器設計模式。
步驟 1
建立服務介面。
Service.java
public interface Service {
public String getName();
public void execute();
}
步驟 2
建立具體的服務。
Service1.java
public class Service1 implements Service {
public void execute(){
System.out.println("Executing Service1");
}
@Override
public String getName() {
return "Service1";
}
}
Service2.java
public class Service2 implements Service {
public void execute(){
System.out.println("Executing Service2");
}
@Override
public String getName() {
return "Service2";
}
}
步驟 3
建立用於 JNDI 查詢的 InitialContext。
InitialContext.java
public class InitialContext {
public Object lookup(String jndiName){
if(jndiName.equalsIgnoreCase("SERVICE1")){
System.out.println("Looking up and creating a new Service1 object");
return new Service1();
}else if (jndiName.equalsIgnoreCase("SERVICE2")){
System.out.println("Looking up and creating a new Service2 object");
return new Service2();
}
return null;
}
}
步驟 4
建立快取。
Cache.java
import java.util.ArrayList;
import java.util.List;
public class Cache {
private List<Service> services;
public Cache(){
services = new ArrayList<Service>();
}
public Service getService(String serviceName){
for (Service service : services) {
if(service.getName().equalsIgnoreCase(serviceName)){
System.out.println("Returning cached "+serviceName+" object");
return service;
}
}
return null;
}
public void addService(Service newService){
boolean exists = false;
for (Service service : services) {
if(service.getName().equalsIgnoreCase(newService.getName())){
exists = true;
}
}
if(!exists){
services.add(newService);
}
}
}
步驟 5
建立服務定位器。
ServiceLocator.java
public class ServiceLocator {
private static Cache cache;
static {
cache = new Cache();
}
public static Service getService(String jndiName){
Service service = cache.getService(jndiName);
if(service != null){
return service;
}
InitialContext context = new InitialContext();
Service service1 = (Service)context.lookup(jndiName);
cache.addService(service1);
return service1;
}
}
步驟 6
使用ServiceLocator演示服務定位器設計模式。
ServiceLocatorPatternDemo.java
public class ServiceLocatorPatternDemo {
public static void main(String[] args) {
Service service = ServiceLocator.getService("Service1");
service.execute();
service = ServiceLocator.getService("Service2");
service.execute();
service = ServiceLocator.getService("Service1");
service.execute();
service = ServiceLocator.getService("Service2");
service.execute();
}
}
步驟 7
驗證輸出。
Looking up and creating a new Service1 object Executing Service1 Looking up and creating a new Service2 object Executing Service2 Returning cached Service1 object Executing Service1 Returning cached Service2 object Executing Service2
傳輸物件模式
當我們想要一次性地將具有多個屬性的資料從客戶端傳遞到伺服器時,可以使用傳輸物件模式。傳輸物件也稱為值物件。傳輸物件是一個簡單的 POJO 類,具有 getter/setter 方法並且是可序列化的,以便它可以傳輸到網路上。它沒有任何行為。伺服器端業務類通常從資料庫中獲取資料並填充 POJO,然後將其傳送到客戶端或按值傳遞。對於客戶端,傳輸物件是隻讀的。客戶端可以建立它自己的傳輸物件並將其傳遞給伺服器,以便一次性更新資料庫中的值。以下是這種設計模式的實體。
業務物件 - 填充傳輸物件的業務服務。
傳輸物件 -簡單的 POJO,只有設定/獲取屬性的方法。
客戶端 - 客戶端向業務物件請求或傳送傳輸物件。
實現
我們將建立一個StudentBO作為業務物件,Student作為代表我們實體的傳輸物件。
我們的演示類TransferObjectPatternDemo在這裡充當客戶端,並將使用StudentBO和Student來演示傳輸物件設計模式。
步驟 1
建立傳輸物件。
StudentVO.java
public class StudentVO {
private String name;
private int rollNo;
StudentVO(String name, int rollNo){
this.name = name;
this.rollNo = rollNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRollNo() {
return rollNo;
}
public void setRollNo(int rollNo) {
this.rollNo = rollNo;
}
}
步驟 2
建立業務物件。
StudentBO.java
import java.util.ArrayList;
import java.util.List;
public class StudentBO {
//list is working as a database
List<StudentVO> students;
public StudentBO(){
students = new ArrayList<StudentVO>();
StudentVO student1 = new StudentVO("Robert",0);
StudentVO student2 = new StudentVO("John",1);
students.add(student1);
students.add(student2);
}
public void deleteStudent(StudentVO student) {
students.remove(student.getRollNo());
System.out.println("Student: Roll No "
+ student.getRollNo() +", deleted from database");
}
//retrive list of students from the database
public List<StudentVO> getAllStudents() {
return students;
}
public StudentVO getStudent(int rollNo) {
return students.get(rollNo);
}
public void updateStudent(StudentVO student) {
students.get(student.getRollNo()).setName(student.getName());
System.out.println("Student: Roll No "
+ student.getRollNo() +", updated in the database");
}
}
步驟 3
使用StudentBO演示傳輸物件設計模式。
TransferObjectPatternDemo.java
public class TransferObjectPatternDemo {
public static void main(String[] args) {
StudentBO studentBusinessObject = new StudentBO();
//print all students
for (StudentVO student : studentBusinessObject.getAllStudents()) {
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
//update student
StudentVO student =studentBusinessObject.getAllStudents().get(0);
student.setName("Michael");
studentBusinessObject.updateStudent(student);
//get the student
studentBusinessObject.getStudent(0);
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
}
步驟 4
驗證輸出。
Student: [RollNo : 0, Name : Robert ] Student: [RollNo : 1, Name : John ] Student: Roll No 0, updated in the database Student: [RollNo : 0, Name : Michael ]