日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

用简单的例子说明提升可复用性的设计模式

發布時間:2024/10/12 asp.net 101 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用简单的例子说明提升可复用性的设计模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

此文寫給想要理解設計模式,但認為《設計模式》中所舉的例子過于復雜的讀者。

為了使程序具有更高的可復用性,前人推薦我們使用如下設計模式:

結構型模式:通過組合類和對象來獲得更大的結構

1. 適配器模式(Adapter)

2. 裝飾器模式(Decorator)

3. 外觀模式(Facade)

行為模式:涉及到算法和對象間職責的分配

1. 策略模式(Strategy)

2. 模板模式(Template)

3. 迭代器模式(Iterator)


1.1 適配器模式

客戶想要根據半徑計算圓的面積(他自己不會算,甚至不知道圓是什么)

public static void main(String[] args) {double radius = 5;System.out.println("我要怎么辦?");}

翻了翻代碼庫,發現有一個已有的工具類Mathematician里有一個計算圓的面積的方法

public class Mathematician {/*** 根據圓的周長計算面積* @param C 圓的周長* @return 圓的面積*/public double CalculateAreaFromPerimeter(double C) {return Math.pow((C / Math.PI / 2), 2) * Math.PI;}}

客戶感到非常絕望,給我打了電話,拜托我給他設計一個新的工具類,能夠實現用半徑算面積的功能。

可問題是我并不會算圓的面積,只會根據半徑算周長。于是我只好想方設法利用已有的方法了。

public class SuperMathTool {private final Mathematician mathematician;/*** 構造方法,需要使用舊的工具類來完成組合* @param mathematician 一個舊的工具類對象*/public SuperMathTool(Mathematician mathematician) {this.mathematician = mathematician;}/*** 根據半徑算圓的周長* @param radius 半徑* @return 圓的周長*/public double CalculateAreaFromRadius(double radius) {double perimeter = 2 * radius * Math.PI;double ans = mathematician.CalculateAreaFromPerimeter(perimeter);return ans;}}

這樣還不算完工。再用接口包裝一下。

public interface MathTool {public double CalculateAreaFromRadius(double radius);}

還要記得讓SuperMathTool實現這個接口。這樣就算完成了。

為什么要用接口呢?我可以寫詳細的Javadoc方便用戶使用,也方便用戶以后擴展,還規定了一個優秀的數學工具類必須有根據圓的半徑計算面積的功能。

為什么要用組合(委派)呢?因為這樣的話,除了計算半徑以外的其他工具方法,都可以委派給舊工具箱類完成,我自己不用重寫實現,也不用復制代碼。

(用繼承的方法也可以實現同樣的功能)

最后,我告訴用戶,我的工具不能單獨使用,想要使用的話就要這樣:

public static void main(String[] args) {double radius = 5;MathTool tool = new SuperMathTool(new Mathematician());tool.CalculateAreaFromRadius(radius);}

1.2 裝飾器模式

客戶想要根據邊長計算正方形的面積(他自己不會算,甚至不知道正方形是什么)

public static void main(String[] args) {double sideLength = 5;System.out.println("怎么辦啊?");}

翻了翻代碼庫,發現有一個已有的數學工具類接口

public interface MathTool {/*** 根據半徑計算的面積* @param radius 半徑* @return 圓的面積*/public double CalculateAreaFromRadius(double radius);}

和它的一個實現類

public class Mathematician implements MathTool {@Overridepublic double CalculateAreaFromRadius(double radius) {double ans = Math.pow(radius, 2) * Math.PI;return ans;}}

這東西只能算圓的面積啊!客戶感到非常絕望,給我打了電話,拜托我給他設計一個新的工具類,能夠實現用邊長算正方形面積的功能,同時不要把舊功能丟掉。

那么我要開始工作了:寫一個新的抽象類實現原接口(防止遺漏原有方法),然后用舊工具類組合,將原有方法委派給它

public abstract class MathToolDecorator implements MathTool {private final MathTool oldTool;/*** 構造方法:完成組合* @param mathematician 舊工具箱對象*/public MathToolDecorator(Mathematician mathematician) {this.oldTool = mathematician;}/*** 原有的方法委派給舊工具箱*/@Overridepublic double CalculateAreaFromRadius(double radius) {return oldTool.CalculateAreaFromRadius(radius);}/*** 根據邊長計算正方形面積* @param sideLength 邊長* @return 正方形面積*/public abstract double CalculateAreaFromSideLength(double sideLength);}

使用抽象類的原因是,計算正方形面積的新方法可能有很多種實現,這樣寫方便以后擴展;并且,除了新方法之外的部分已經在抽象類中寫好了,一勞永逸,以后寫不同實現時就只用寫正方形,原有方法就不用再寫了(等下就能看到)。

接下來,在具體類中完成計算正方形面積的實現:

public class ConcreteMathToolDecorator extends MathToolDecorator {/*** 構造方法:直接調用抽象類構造方法即可* @param mathematician*/public ConcreteMathToolDecorator(Mathematician mathematician) {super(mathematician);}@Overridepublic double CalculateAreaFromSideLength(double sideLength) {double ans = Math.pow(sideLength, 2);return ans;}}

這樣就算完成了。最后告訴用戶應該樣使用:

public static void main(String[] args) {double sideLength = 5;MathToolDecorator tool = new ConcreteMathToolDecorator(new Mathematician());tool.CalculateAreaFromSideLength(sideLength);}

1.3 外觀模式

用戶想要計算a * b mod c,他想要調用已有的方法來完成這個復雜的計算。他翻了翻代碼庫,找到了這個工具類:

public class SuperMathTool {/*** 計算a + b* @param a * @param b* @return a + b*/public int plus(int a, int b) {return a + b;}/*** 計算a % b* @param a* @param b* @return a % b*/public int mod(int a, int b) {return a % b;}}

這些計算非常精妙,但想要完成計算必須反復調用它們很多次,實在是太繁瑣了!用戶覺得懶得動彈,于是給我打了電話,讓我寫一個方便計算a * b mod c的工具類。

這不難做,把繁瑣的操作包裝起來方便用戶使用,這是我的強項。

public class EasyTool {private final SuperMathTool tool = new SuperMathTool();/*** 一個簡便的操作* 計算a * b mod c*/public int calculate(int a, int b, int c) {int ans = 0;for (int i = 1; i <= b; i++) {ans = tool.plus(a, i);}ans = tool.mod(ans, c);return ans;}}

最后,告訴用戶這樣使用:

public class Main {public static void main(String[] args) {int a = 53;int b = 97;int c = 89;EasyTool tool = new EasyTool();tool.calculate(a, b, c);}}

兩行即可解決問題!


2.1 策略模式

眾所周知,java的整數乘法乘法有兩種實現方式,一種是直接乘起來,另一種是累加。

大豬頭最近正在設計一個數學工具類,其中有一個方法就是計算乘法。

public class MathTool {/*** 整數加法*/public int plus(int a, int b) {return a + b;}/*** 整數乘法*/public int multiply(int a, int b) {return a * b;}}

但他認為這不夠完美,因為他實現乘法的方式是固定的。他有一個想法:讓用戶在運行時,動態地決定用哪種實現方式來計算乘法。于是我建議他使用策略模式:

1. 首先寫一個策略接口,聲明一下將要完成什么工作

public interface Strategy {/*** 計算整數乘法a * b* @param a* @param b* @return a * b*/public int multiply(int a, int b);}

2. 寫出兩種不同的實現

/*** 乘法的第一種實現*/ public class Strategy1 implements Strategy {@Overridepublic int multiply(int a, int b) {int ans = a * b;return ans;}} /*** 乘法的第二種實現*/ public class Strategy2 implements Strategy {@Overridepublic int multiply(int a, int b) {int ans = 0;for (int i = 1; i <= b; i++) {ans += a;}return ans;}}

3. 將Strategy組合到原有的數學工具類中:

public class MathTool {private final Strategy strategy;/*** 構造方法:完成組合* @param strategy 將要使用的乘法策略*/public MathTool(Strategy strategy) {this.strategy = strategy;}

然后計算乘法的部分委派給strategy完成

/*** 整數加法*/public int plus(int a, int b) {return a + b;}/*** 整數乘法*/public int multiply(int a, int b) {return strategy.multiply(a, b);}}

完成啦。

這樣,用戶使用MathTool的自由度就更大啦,比如:

public static void main(String[] args) {MathTool tool1 = new MathTool(new Strategy1());tool1.multiply(3, 4);MathTool tool2 = new MathTool(new Strategy2());tool2.multiply(5, 6);}

2.2 模板模式

大豬頭打算設計一系列游戲,我建議他采用模板模式,因為盡管游戲內容不同,所有游戲都有相同的三個步驟:

1. 初始化

2. 開始

3. 結束

不同游戲的區別在于,這三個步驟的具體實現是不同的,但不同的游戲都必須按這個順序執行這三個步驟,這個順序是固定的。

先寫一個游戲的抽象類:

public abstract class Game {/*** 模板方法:按照特定順序調用其他方法完成操作* 注意:加上final標簽防止被重寫*/public final void play(){//初始化游戲 initialize();//開始游戲 startPlay();//結束游戲 endPlay();}abstract void initialize();abstract void startPlay();abstract void endPlay();}

它有一個final的模板方法,規定了各個操作的順序,要求無論什么樣的實現都必須按照這個順序執行。

它的不同實現需要重寫初始化、開始、結束的操作:

/*** 足球游戲*/ public class Football extends Game {@Overridevoid initialize() {System.out.println("足球游戲初始化中...");}@Overridevoid startPlay() {System.out.println("足球游戲開始!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}@Overridevoid endPlay() {System.out.println("足球游戲結束!");}} /*** 拳擊游戲*/ public class Boxing extends Game {@Overridevoid initialize() {System.out.println("拳擊游戲初始化中...");}@Overridevoid startPlay() {System.out.println("拳擊游戲開始!");try {Thread.sleep(1500);} catch (InterruptedException e) {e.printStackTrace();}}@Overridevoid endPlay() {System.out.println("拳擊游戲結束!");}}

用戶使用的方法如下:

public static void main(String[] args) {Game game1 = new Football();game1.play();Game game2 = new Boxing();game2.play();}

2.3 迭代器模式

大豬頭設計了一個模擬行星系中行星運動的軌道系統:

public class CircularOrbit {private Map<Double, String> objects = new HashMap<>();// AF// objects是軌道系統各物體按照其軌道半徑的索引
? //? ?Map<Double, String>中,Double是軌道半徑,String是物體名稱

為了方便地訪問各個軌道物體(并且最好能從軌道半徑從小到大訪問),他需要給這個ADT實現Iterable接口,

public class CircularOrbit implements Iterable {

然后實現Iterator方法:

@Overridepublic Iterator<String> iterator() {return new OrbitIterator(this);}

這個OrbitIterator是自己定義的一個迭代器類(當然了,Java可不知道我們會設計怎樣的ADT,當然不可能給我們準備好Iterator)

最好能寫成內部類,更加安全。以下展示CircularOrbit的完成版本:

public class CircularOrbit implements Iterable<String> {private Map<Double, String> objects = new HashMap<>();// AF// objects是軌道系統各物體按照其軌道半徑的索引// Map<Double, String>中,Double是軌道半徑,String是物體名稱 @Overridepublic Iterator<String> iterator() {return new OrbitIterator(this);}class OrbitIterator implements Iterator<String> {private final List<String> objs = new ArrayList<>();private int index;// AF// objs按從里向外的順序儲存軌道系統中的軌道物體// index表示當前遍歷到的元素在list中的下標// RI// index >= 0// Safety// index是private的不可變類// objs是private final的可變類,且沒有操作向外返回該對象/*** 構造方法:將CircularOrbit中的物體有里向外存在list中* @param c 軌道系統對象*/private OrbitIterator(CircularOrbit c) {List<Double> radiuses = new ArrayList<>();radiuses.addAll(c.objects.keySet());radiuses.sort(Comparator.naturalOrder());for (int i = 0; i < radiuses.size(); i++) {objs.add(c.objects.get(radiuses.get(i)));}index = 0;}@Overridepublic boolean hasNext() {if (index < objs.size()) return true;elsereturn false;}@Overridepublic String next() {return objs.get(index);}}}

注意:Iterable和Iterator后的尖括號中寫的是想要讓Iterator.next()返回的對象類型。

用戶使用方法如下:

public static void main(String[] args) {CircularOrbit c = new CircularOrbit();Iterator<String> it = c.iterator();while (it.hasNext()) System.out.println(it.next());}

舉例就到此結束了。

為了方便理解,選用了過分簡單的例子,請多多包涵。

?

轉載于:https://www.cnblogs.com/snt165/p/11074668.html

總結

以上是生活随笔為你收集整理的用简单的例子说明提升可复用性的设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。