W3Techs shows which web technologies Soliton-music.com is using.
𓃗
Mike Driver
he wasn't even looking at me and he found me

tannertan36
almost home
Not today Justin

bliss lane
No title available
The Bowery Presents
Cosmic Funnies

Product Placement
noise dept.

ellievsbear
h
NASA
let's talk about Bridgerton tea, my ask is open
No title available
Xuebing Du
★

roma★
seen from Pakistan
seen from Vietnam
seen from United Kingdom
seen from Malaysia

seen from Ukraine
seen from Maldives
seen from Philippines

seen from Thailand

seen from United States
seen from Argentina
seen from Türkiye

seen from United States

seen from United States
seen from Pakistan
seen from United States

seen from Maldives
seen from Nepal

seen from Türkiye
seen from Kenya

seen from South Africa
@benccwai-blog
W3Techs shows which web technologies Soliton-music.com is using.
+) (template) (.NET) (C#)
Abstract Head First Design Patterns是用strategy pattern當作第一個範例,而陳俊杉教授也是用strategy當作授課的第一個pattern,可見strategy的確適合初學者學第一個學習的pattern。 Intent 定義一整族演算法,將每一個演算法封裝起來,可互換使用,更可以在不影響外界的情況下各別抽換所引用的演算法。 其UML表示法 GoF說strategy也稱為policy,我個人喜歡稱它為plugin,因為可以動態的換演算法,如同在eclipse上可以動態的換plugin一樣。 原本在單一class中有一個單一method很單純,如圖Grapher class只有drawShape()這個method,只能畫方形。 但後來『需求改變』,希望Grapher也能畫三角形和圓形,而且日後還可能增加功能,如畫橢圓形,菱形...,當然可以在Grapher陸續加上drawTriangle(),drawCircle(),drawEllipse(),但如此就違反OCP,Grapher須不斷的修改,根據DP第三守則"Identify the aspects of your application that vary and separate them from what you stays the same",將『會變』的部份另外包成class,但這些class必須要和原來的class溝通,所以必須訂出『標準』彼此才能溝通,IShape就是彼此溝通的標準,Triangle,Circle,Square則必須實做IShape這個interface,這就是strategy pattern。 我們看看這個架構,若日後還有新的shape加入,Grapher,IShape,Triangle,Circle,Square皆不用修改,符合OCP的closed for modification原則,若要加入新的class,只需實做IShape即可,符合OCP的open for extension原則,所以是非常好維護的架構,事實上,.NET Framework和STL都用了很多strategy pattern。
簡言之,strategy pattern就是將會變動的member function用class包起來,變成object『掛』在原本的class上。
ISO C++ by Interface
1/* 2(C) OOMusou 2007 http://oomusou.cnblogs.com 3 4Filename : DP_StrategyPattern_Classic.cpp 5Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++ 6Description : Demo how to use Strategy Pattern 7Release : 03/26/2007 1.0 8 07/10/2007 2.0 9*/ 10#include <iostream> 11using namespace std; 12 13class IDrawStrategy { 14public: 15 virtual void draw() const = 0; 16}; 17 18class Grapher { 19public: 20 Grapher(IDrawStrategy* drawStrategy = 0) : _drawStrategy(drawStrategy) {} 21 22public: 23 void drawShape() const; 24 void setShape(IDrawStrategy* drawStrategy); 25 26protected: 27 IDrawStrategy* _drawStrategy; 28}; 29 30void Grapher::drawShape() const { 31 if (_drawStrategy) 32 _drawStrategy->draw(); 33} 34 35void Grapher::setShape(IDrawStrategy* drawStrategy) { 36 _drawStrategy = drawStrategy; 37} 38 39class Triangle : public IDrawStrategy { 40public: 41 void draw() const; 42}; 43 44void Triangle::draw() const { 45 cout << "Draw Triangle" << endl; 46} 47 48class Circle : public IDrawStrategy { 49public: 50 void draw() const; 51}; 52 53void Circle::draw() const { 54 cout << "Draw Circle" << endl; 55} 56 57class Square : public IDrawStrategy { 58public: 59 void draw() const; 60}; 61 62void Square::draw() const { 63 cout << "Draw Square" << endl; 64} 65 66int main() { 67 Grapher grapher(&Square()); 68 grapher.drawShape(); 69 70 grapher.setShape(&Circle()); 71 grapher.drawShape(); 72}
執行結果
Draw Square Draw Circle
67行和70行可以看到strategy pattern的美,可以動態的換演算法,如同plugin一樣,且若將來擴充其他shape,只需加上新的class實做IDrawStrategy,其他程式都不用再改,符合OCP原則。 C# by Interface
1/* 2(C) OOMusou 2007 http://oomusou.cnblogs.com 3 4Filename : DP_StrategyPattern_Classic.cs 5Compiler : Visual Studio 2005 / C# 2.0 6Description : Demo how to implement Strategy Pattern by C# 7Release : 07/08/2007 1.0 8*/ 9using System; 10 11interface IDrawStrategy { 12 void draw(); 13} 14 15class Grapher { 16 private IDrawStrategy _drawStrategy = null; 17 18 public Grapher() {} 19 public Grapher(IDrawStrategy drawStrategy) { 20 _drawStrategy = drawStrategy; 21 } 22 23 public void drawShape() { 24 if (_drawStrategy != null) 25 _drawStrategy.draw(); 26 } 27 28 public void setShape(IDrawStrategy drawStrategy) { 29 _drawStrategy = drawStrategy; 30 } 31} 32 33class Triangle : IDrawStrategy { 34 public void draw() { 35 Console.WriteLine("Draw Triangle"); 36 } 37} 38 39class Circle : IDrawStrategy { 40 public void draw() { 41 Console.WriteLine("Draw Circle"); 42 } 43} 44 45class Square : IDrawStrategy { 46 public void draw() { 47 Console.WriteLine("Draw Square"); 48 } 49} 50 51class Program { 52 public static void Main() { 53 Grapher grapher = new Grapher(new Square()); 54 grapher.drawShape(); 55 56 grapher.setShape(new Circle()); 57 grapher.drawShape(); 58 } 59}
執行結果
Draw Square Draw Circle
使用interface是最正規的OOP寫法,另外Effective C++的item 35也使用了function pointer來實做strategy pattern,function pointer是C/C++的獨門寫法。 ISO C++ by Function Pointer
1/* 2(C) OOMusou 2007 http://oomusou.cnblogs.com 3 4Filename : DP_StrategyPattern_FunctionPointer.cpp 5Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++ 6Description : Demo how to use Strategy Pattern by function pointer 7Release : 03/31/2007 1.0 8 : 07/08/2007 2.0 9 : 07/10/2007 3.0 10*/ 11#include <iostream> 12 13using namespace std; 14 15class Grapher { 16public: 17 typedef void (*pfDraw)(); 18 Grapher(pfDraw draw = 0) : _draw(draw) {} 19 20public: 21 void drawShape() const; 22 void setShape(pfDraw draw); 23 24protected: 25 pfDraw _draw; 26}; 27 28void Grapher::drawShape() const { 29 if (_draw) 30 _draw(); 31} 32 33void Grapher::setShape(pfDraw draw) { 34 _draw = draw; 35} 36 37class Triangle { 38public: 39 static void draw(); 40}; 41 42void Triangle::draw() { 43 cout << "Draw Triangle" << endl; 44} 45 46class Circle { 47public: 48 static void draw(); 49}; 50 51void Circle::draw() { 52 cout << "Draw Circle" << endl; 53} 54 55class Square { 56public: 57 static void draw(); 58}; 59 60void Square::draw() { 61 cout << "Draw Square" << endl; 62} 63 64int main() { 65 Grapher grapher(Square::draw); 66 grapher.drawShape(); 67 68 grapher.setShape(Circle::draw); 69 grapher.drawShape(); 70}
執行結果
Draw Square Draw Circle
說穿了,本來只是本來由interface定義function的signature,現在改由16行的
typedef void (*pfDraw)();
定義pfDraw這個function pointer型別,所有要傳進的的function必須符合這個function pointer型別才可。 既然ISO C++可以用function pointer實現strategy pattern,就讓我想到C#的delegate了。delegate是C#對function pointer和observer pattern的實現,理應可用delegate來實現strategy pattern。 C# by Delegate
1/* 2(C) OOMusou 2007 http://oomusou.cnblogs.com 3 4Filename : DP_StrategyPattern_Delegate.cs 5Compiler : Visual Studio 2005 / C# 2.0 6Description : Demo how to implement Strategy Pattern by C# delegate 7Release : 07/08/2007 1.0 8*/ 9using System; 10 11class Grapher { 12 private DrawDelegate _drawDelegate = null; 13 14 public delegate void DrawDelegate(); 15 16 public Grapher() {} 17 public Grapher(DrawDelegate drawDelegate) { 18 _drawDelegate = drawDelegate; 19 } 20 21 public void drawShape() { 22 if (_drawDelegate != null) 23 _drawDelegate(); 24 } 25 26 public void setShape(DrawDelegate drawDelegate) { 27 _drawDelegate = drawDelegate; 28 } 29} 30 31class Triangle { 32 public static void draw() { 33 Console.WriteLine("Draw Triangle"); 34 } 35} 36 37class Circle { 38 public static void draw() { 39 Console.WriteLine("Draw Circle"); 40 } 41} 42 43class Square { 44 public static void draw() { 45 Console.WriteLine("Draw Square"); 46 } 47} 48 49class Program { 50 public static void Main() { 51 Grapher grapher = new Grapher(Square.draw); 52 grapher.drawShape(); 53 54 grapher.setShape(Circle.draw); 55 grapher.drawShape(); 56 } 57}
執行結果
Draw Square Draw Circle
除此之外,GoF的Design Pattern也展示了使用template實做Strategy Pattern。 ISO C++ by Template
1/* 2(C) OOMusou 2007 http://oomusou.cnblogs.com 3 4Filename : DP_StrategyPattern_template.cpp 5Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++ 6Description : Demo how to use Strategy Pattern by template 7Release : 03/31/2007 1.0 8*/ 9#include <iostream> 10 11using namespace std; 12 13template <typename T> 14class Grapher { 15private: 16 T _drawTemplate; 17 18public: 19 void drawShape() const; 20}; 21 22template<typename T> 23void Grapher<T>::drawShape() const { 24 _drawTemplate.draw(); 25} 26 27class Triangle { 28public: 29 void draw() const; 30}; 31 32void Triangle::draw() const { 33 cout << "Draw Triangle" << endl; 34} 35 36class Circle { 37public: 38 void draw() const; 39}; 40 41void Circle::draw() const { 42 cout << "Draw Circle" << endl; 43} 44 45class Square { 46public: 47 void draw() const; 48}; 49 50void Square::draw() const { 51 cout << "Draw Square" << endl; 52} 53 54int main() { 55 Grapher<Square> grapher; 56 grapher.drawShape(); 57 58 Grapher<Circle> grapher2; 59 grapher2.drawShape(); 60}
執行結果
Draw Square Draw Circle
同樣是實現多型,Design Pattern的用的是OOP的interface + dynamic binding技術,這是在run-time下完成,優點是在run-time動態改變,缺點是速度較慢;GP用template技術,這是在compile-time下完成,優點是速度較快,缺點是無法在run-time動態改變,由於template方式不需interface,所以整個程式看不到interface,也由於無法run-time改變,所以沒有setShape(),而16行的
T _drawTemplate;
也只是object而非pointer,因為不需run-time的多型,也非function pointer。 46行
Grapher<Square> grapher;
也只能在直接指定strategy,無法動態再改變。 C# 2.0也提供泛型了,所以C#也可以用Generics實現Strategy Pattern。 C# by Generics
1/* 2(C) OOMusou 2007 http://oomusou.cnblogs.com 3 4Filename : DP_StrategyPattern_Generics.cs 5Compiler : Visual Studio 2005 / C# 2.0 6Description : Demo how to implement Strategy Pattern by C# Generics 7Release : 07/08/2007 1.0 8*/ 9using System; 10 11interface IDrawStrategy { 12 void draw(); 13} 14 15class Grapher<T> where T : class, IDrawStrategy, new() { 16 private T _drawStrategy = default(T); 17 18 public Grapher() { 19 _drawStrategy = new T(); 20 } 21 22 public void drawShape() { 23 if (_drawStrategy != null) 24 _drawStrategy.draw(); 25 } 26 27 public void setShape(T drawStrategy) { 28 _drawStrategy = drawStrategy; 29 } 30} 31 32class Triangle : IDrawStrategy { 33 public void draw() { 34 Console.WriteLine("Draw Triangle"); 35 } 36} 37 38class Circle : IDrawStrategy { 39 public void draw() { 40 Console.WriteLine("Draw Circle"); 41 } 42} 43 44class Square : IDrawStrategy { 45 public void draw() { 46 Console.WriteLine("Draw Square"); 47 } 48} 49 50class Program { 51 public static void Main() { 52 Grapher<Square> grapher = new Grapher<Square>(); 53 grapher.drawShape(); 54 55 Grapher<Circle> grapher2 = new Grapher<Circle>(); 56 grapher2.drawShape(); 57 } 58}
執行結果
Draw Square Draw Circle
Remark strategy和template method目的相同,皆對『新需求』的不同演算法提供『擴充』的機制,但手法卻不同,strategy採用object的方式,利用delegation改變演算法,而template method則採用class的繼承方式來改變演算法,也因為strategy採用object方式,所以有run-time改變的可能,但template method採class手法,所以無法run-time改變。 GoF的原文如下
Template methods use inheritance to vary part of an algorithm. Strategies use delegation to vary the entire algorithm.
Known Use 1.eclipse的plugin,可以在不修改eclipse原始碼下,外掛plugin變更eclipse所提供的功能。
See Also (原創) 我的Design Pattern之旅[2]:Template Method Pattern (OO) (Design Pattern) (C/C++) (原創) 我的Design Pattern之旅[3]:使用template改進Strategy Pattern (OO) (Design Pattern) (C/C++) (template) Reference GoF,Design Patterns,Addison Weseley Longman,1995 A. Shalloway,J. R. Trott,Design Patterns Explained 2/e,Addison Wesley, 2005 Eric Freeman,Elisabeth Freeman,Head First Design Pattern,O'Reilly,2004 Robert C. Martin,Agile Software Development,Pearson Prentice Hall, 2002 Scott Meyers,Effective C++ 3/e Item 35,Addison Wesley, 2005
Install Chromium, upgrade it to Chrome OS and Dual boot
Install Chromium, upgrade it to Chrome OS and Dual boot
Chromium OS As many of you know 'chromium OS' is an open source operating system that has been made famous by the amazing Hexxeh. Since then, many people have often wondered on how to install this to a hard drive? Is it possible to get Chrome OS not Chromium? Can I dual boot this? Fortunately for everyone who wishes to do any or all of these it is perfectly possible. The total amount of time for to complete all of the instructions should be about thirty minutes in total; this includes downloading of the Chromium OS, installing and downloading and installing the Chrome OS operating system over the top. Chrome OS also includes all the codecs and missing pieces from Hexxeh's Chromium build such as flash and mp3. Please read the disclaimer at the bottom of this article before proceeding. Not all hardware will boot Chromium and Chrome OS. I SHALL NOT GIVE OUT INSTRUCTIONS ON HOW TO CREATE A CHROME NUMBER TO RECEIVE THE GOOGLE DRIVE OFFER! DON'T ASK! How to install Chromium OS. Before you can get the official builds of Chrome OS you must first install Chromium onto your hard drive. To do this you must first make a bootable Chromium usb drive as described on Hexxeh's site here. Hexxeh gives very simple instructions on how to do this. Once you have made your bootable memory stick you then need to boot from it and quickly set it up so you can begin installing it to your HDD/SDD. NOTE: Not all graphic cards are supported, if you get a blank screen before or after the Chromium logo then try the on board graphics if possible, if not, your hardware may not work with Chromium. if you wish to dual boot you will need two HDD's as it is not possible to dual boot from just one. follow the instructions to dual boot at the bottom of this article! Warning! Installing Chromium into a hard drive formats the entire drive not just a partition. If you wish to dual boot you will need two HDD's as it is not possible to dual boot from just one. follow the instructions to dual boot at the bottom of this article! To install chromium simply boot into Chromium from the memory stick press and hold ctrl + alt and press t (you may need to alternate pressing alt and t while holding ctrl) and this will bring you to the Crosh command. Do this once you have logged in. Here you will need to run the command: install You will then be prompt for the username and password which are: Username = chromos Password = facepunch Some users will ONLY be asked for the password You will then have a few prompts to confirm you will lose all data etc, agree to all of these and Chromium will begin installing on your HDD, this took about two minutes on my currently set up with an i3. Once Chromium has installed simply turn off your computer, remove your memory stick and turn back on. You have now installed Chromium on your HDD. You are now free to format your memory stick, HDD guru is the best tool to format as it is free and will format drives without damaging them, it also allows for low level format although you only need to remove the MBR. HOW TO UPGRADE CHROMIUM TO CHROME OS! The advantage about upgrading to Chrome OS is the added codecs and other little things that due to licencing Hexxeh is unable to give out but its already in Chrome OS. Before proceeding make sure you are logged into chromium and NOT using a guest account. To install Chrome OS is very simple, first you need to boot into a HDD installed Chromium OS and open the developer console CTRL + ALT + F2 ( you may need to alternate ALT and F2 while holding control. Here you will need to type the command: sudo su Then you will need to follow the prompts for username and password as listed above and confirm that you agree with the shown agreement. There is now one more command that you will need to run that is the final step in installing Chrome OS. wget http://goo.gl/4suhf; sudo bash 4suhf Type the above command and then press enter. you will now be given the options for 13 different builds of Chrome OS, each build is for a different install such as the series 3 samsung chromebook, the series 5 chromebook, the series 3 chromebox and other chromebooks. Pick the build of Chrome OS you would like be typing the corresponding number and pressing enter. The script will then begin to download and install your Chrome OS for you, this will take about 5 minutes on a 100mb internet connection. Once the script has finished running you are ready to reboot. ( you will know if the script has finished running as you won't be able to exit the developer console ( ctrl+alt+F1)) Reboot and you will now have Chrome OS installed!!! If Chrome OS then does NOT boot, the image of your chosen Chrome OS install simply doesn't work on your hardware so just repeat the install of Chromium and try another build, if none of the recovery images boot then you will not be able to use Chrome OS and will have to stick with Chromium. Once Chrome OS has been installed and you have logged in you will receive an error stating that your account has been used on a higher build number than the current install, all this means is that your user profile has been loaded from the chromium install from earlier and as chromium uses a newer source code Chrome OS thinks you have downgraded, to fix this simply go into settings -> advanced settings -> power wash, let this run for about two minutes and you will be good to go. YOU WILL LOSE ALL DATA WHEN DOING THIS!!!! Dual boot ANY OS and Chrome OS! Dual booting with Chrome OS is very simple if you wish to have ANY other operating system installed along side it. You can only dual boot using two HDD's as installing Chromium requires formatting the entire HDD and you then have no way of partitioning the drive until it is formatted. Simply remove the HDD with the operating system you currently use so you only have the hdd you wish to have Chromium/Chrome OS installed one and then the follow the steps to install Chromium/Chrome OS. Once you are satisfied with your Chromium/Chrome OS install, simply reinstall your original HDD to your computer and then pick your boot order in the bios. If you wish to boot to the other drive then you simply pick it as a temp boot during the boot sequence. Disclaimer: Auto-updates do not work on factory recovered Chrome installs and as such, to upgrade, the entire set up must be completed from a clean install of Chromium. I take no responsibility for any loss of data or damage to hardware or software that was caused by following these instructions. By following these instructions you do so at your own risk, understanding that with all operating system installs there is the risk of damage.
樱桃小丸子粤语tvb粤语
bilibili是一家弹幕站点,大家可以在这里找到许多的欢乐.
I’ve mentioned this in previous tutorials, but I keep forgetting to make a point out of it.
One great performance trick when using gpu renderMode on mobile, is to add this single line of code: stage.quality = “low”;
On Android and Playbook, this can almost double your framerate without comprimising image quality at all. (Provided you use bitmap’s to render everything :p). On iOS the effects seem to be negligible. you can get a huge boost on older devices such as iPad 1 or 3GS, but the difference on newer devices like the iPad 2 seemed to be negligible from my testing.
Rather than charts I will simply give you two screenshots from my Galaxy Nexus:
The only difference in these two apps is the stage quality. And as you can see, they look identical.
The reason’s this works is because LOW stage quality still allows textFields to be rendered perfectly, and it also respects abitmap.smoothing = true, or a draw() call with smoothing set to true. So text looks perfect, bitmap’s look perfect that’s almost everything… all that’s left are those pesky vector’s animations.
To render Vector’s with LOW stage quality, there’s an easy trick:
set stage.quality = HIGH
cache vector to bitmapData
set stage.quality = LOW
Like So:
0 1 2 3 4 5 6 7 8 9 10
stage.quality = StageQuality.HIGH; var asset:Sprite = new LibraryVectorAsset(); var bitmapData:BitmapData = new BitmapData(asset.width, asset.height, false, 0x0); bitmapData.draw(vectorAsset); //Here's our smoothly rendered vector :) var cachedVector:Bitmap = new Bitmap(); addChild(cachedVector); //Lets get that performance boost back stage.quality = StageQuality.LOW;
This can be expanded upon by passing a matrix to pre-scale the vector to any size you see fit, just make sure to set smoothing=true in your draw() call.
If you've read a Head First book, you know what to expect--a visually rich format designed for the way your brain works. Using the latest research in neurobiology, cognitive science, and learning theory, Head First Design Patterns will load patterns
[PHP] 該用 Abstract Class 還是 Interface ?
2007-08-24
這裡把自己對 Abstract Class (抽象類別) 和 Interface (介面) 的理解記一下,如果有錯請指正我 :)
Abstract Class 與 Interface 的宣告方式
Abstract Class 和 Interface 本身都無法用來建構一個 object (物件實體) ,它們必須透過其他類別以 extends (繼承) 或 implements (實作) 來完成目的。在 PHP 中,我們可以用以下的方式來宣告一個 Abstract Class :
1 2 3 4
abstract class Test { // ... code ... }
然後其 sub class 必須用 extends 來繼承它:
1 2 3 4
class ClassA extends Test { // ... code ... }
而 Interface 則是用以下的方式宣告:
1 2 3 4
interface Testable { // ... code ... }
然後 sub class 類別便可以 implements 關鍵字來實作該介面:
1 2 3 4
class ClassB implements Testable { // ... code ... }
註:同人老大說實作 Interface 的類別不能稱為 sub class ,不過我實在也想不出什麼好名詞,歡迎大家提供意見。
另外比較特別的是, Interface 可以繼承衍生自另一個 Interface :
1 2 3 4
interface A extends B { // ... code ... }
這裡本來用繼承一詞,經同人老大指點後,用衍生一詞會比較精準。
但是除了語法上的不同,它們本身所代表的意義是什麼呢?
Abstract Class
當整個類別繼承體系有一致的行為時,我們通常會將這些行為抽離到上一層的 super class 去。如果這些行為的程式碼不在 super class 中定義的話,那麼會使得其 sub class 必須重覆地出現相同的程式片段,導致了壞味道的發生。然而有時我們並不打算讓這些 super class 可以被建構成物件實體,那麼它們就是所謂的 Abstract Class 。
在 Abstract Class 中, method 的定義方式有兩種,以下是有實作的 method :
1 2 3 4
public function method1() { // ... code ... }
值得注意的是,就算大括號中沒有程式碼,也算是有實作的 method ,我稱之為空實作。
另一種是抽象方法,只要在 function 前加上 abstract 關鍵字,再拿掉大括號並加上分號:
1
abstract public function method2();
這樣的抽象方法,就會要求 sub class 在繼承之後要實作該方法的細節。
Interface
在我們確定了物件之間的溝通方式及規格,卻未能確定其實作細節時,就是利用 Interface 的時機。 Interface 能保證 Client 在操作物件上有一致的方式,而具體的表現方式則是讓實作的類別來決定。因此這些類別都必須實作在 Interface 裡定義的 method ,否則將會出現錯誤。在 Interface 中所有方法都是 abstract 的,定義方式和 Abstract Class 的抽象方法一樣,但是不用加上 abstract 關鍵字,例如:
1
public function method3();
顯然地,當 Abstract Class 所擁有的方法都是 abstract method 時,它就退化成了一個 Interface 。不過還是要小心以下兩點:
一個 Class 可以實作多個 Interface ,但只能繼承一個 Abstract Class ;這即是所謂的單一繼承體系,也就是子類別只能繼承一個父類別;但是一個父類別則可以被多個子類別所繼承。
在 Abstract Class 中可以宣告屬性成員 (attribute) 而 Interface 是不可以的,但兩者都能有常數成員 (constant) 。
範例
假設我們有兩個裝置 (Device) ,一個是鍵盤 (Keyboard) ,一個是滑鼠 (Mouse) ;而這兩種裝置都支援 USB 和 PS/2 兩種接頭 (Adapter) 讓使用者可以自行選擇,不過一次只能選擇一種接頭。
註:這個範例舉得不是很好,只是為了說明而已。
上面文字明白指出了我們可能會有 Device 和 Adapter 兩個 Abstract Class (或 Interface ) ,不過問題是哪一個應該用 Abstract Class ?而哪一個該用 Interface 呢?
為了簡化說明,我們把原來的問題重新定義為以下的規格:
Device 有 inputData (輸入資料) 及 getStatus (取得狀態) 等兩個方法。
Adapter 有 send (傳送) 和 receive (接收) 兩個方法。
Device 必須透過 Adapter 來傳送或接收資料。
我們從規格的第三點可以得知,無論 Device 的類型為何,都會需要透過 Adapter 來收送資料,這就是一種抽象行為。也因此我們必須為 Device 提供一個 Adapter 類型的 $_adapter 屬性成員,從這點就可以看出 Device 應該是個 Abstract Class 。
而因為有 $_adapter 屬性,但我們又不想讓外界直接改變它,所以我們將它的 scope 設置為 private (私有屬性) ;然而要設定 private attribute 我們就要借重一個規格外的方法,這裡我將它命名為 setAdapter ;所以當我們在呼叫 setAdapter 時就必須傳入一個 Adapter 物件來指定給 $_adapter 屬性,這樣就能防止 Device 在使用 $_adapter 時的錯誤。
1 2 3 4
public function setAdapter(Adapter $adapter) { $this->_adapter = $adapter; }
然後 Device 的 inputData 和 getStatus 就會委託 Adapter 物件的 send 及 receive 來收送資料:
1 2 3 4 5 6 7 8 9 10
public function inputData($data) { echo $this->_deviceName, ' input data:'; $this->_adapter->send($data); } public function getStatus() { echo $this->_deviceName, ' get status:'; echo $this->_adapter->receive(); }
註:以上程式還是有一些潛在的小問題,這裡就留給各位自行判斷囉。
對 Device 的 sub class 來說,以上的行為都是可以共用,也因此不必再實作一次了。完整的 Device 類別體系如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
<?php abstract class Device { private $_adapter = null; protected $_deviceName = ''; public function setAdapter(Adapter $adapter) { $this->_adapter = $adapter; } public function inputData($data) { echo $this->_deviceName, ' input data:'; $this->_adapter->send($data); } public function getStatus() { echo $this->_deviceName, ' get status:'; echo $this->_adapter->receive(); } } class Device_Keyboard extends Device { protected $_deviceName = 'Keyboard'; } class Device_Mouse extends Device { protected $_deviceName = 'Mouse'; }
接著再看 Adapter ,因為 USB 和 PS/2 在規格實作上是有所差異的,因此我們無法在 Adapter 中直接去定義像 Device 中 inputData 及 getStatus 這樣共用的行為方法。所以在這裡我們就能將 Adapter 視為是一個 Interface ,讓其下的 Class 去實作 send 和 receive 兩個方法的細節。所以整個 Adapter 的類別體系如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
<?php interface Adapter { public function send($data); public function receive(); } class Adapter_Ps2 implements Adapter { public function send($data) { echo $data, ' by PS2.', "\n"; } public function receive() { return rand(100, 200) . ' by PS2.' . "\n"; } } class Adapter_Usb implements Adapter { public function send($data) { echo $data, ' by USB.', "\n"; } public function receive() { return rand(300, 400) . ' by USB.' . "\n"; } }
註:為了說明方便,所以我簡化了 USB 和 PS/2 的兩個方法的實作方式。
當然 Adapter 也不一定要是 Interface 才行,這得看整個程式架構上的設計來判斷。如果在 Adpater 在設計上會有共用的行為或屬性時,那麼 Abstract Class 就是比較好的選擇;只是在這個範例裡,我為了說明 Interface 的緣故,就大幅簡化了 Adapter 的設計。
整個設計用 UML 來表示的話,就是以下這樣子:
以下是測試的程式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
<?php require_once 'Device.php'; require_once 'Adapter.php'; $keyboard = new Device_Keyboard(); $mouse = new Device_Mouse(); echo "\n"; $keyboard->setAdapter(new Adapter_Ps2()); $keyboard->inputData('abc'); $keyboard->getStatus(); echo "\n"; $mouse->setAdapter(new Adapter_Ps2()); $mouse->inputData('def'); $mouse->getStatus(); echo "\n"; $keyboard->setAdapter(new Adapter_Usb()); $keyboard->inputData('abc'); $keyboard->getStatus(); echo "\n"; $mouse->setAdapter(new Adapter_Usb()); $mouse->inputData('def'); $mouse->getStatus(); /* 程式執行結果: ==================================================== Keyboard input data:abc by PS2. Keyboard get status:130 by PS2. Mouse input data:def by PS2. Mouse get status:165 by PS2. Keyboard input data:abc by USB. Keyboard get status:360 by USB. Mouse input data:def by USB. Mouse get status:353 by USB. ==================================================== */
完整範例下載
結論
很多時候我們常會搞不清楚該用 Abstract Class 還是 Interface ,其實這在設計階段是常有的事情。所以掌握以下的重點,就會比較容易看出兩者的使用時機:
當類別有共同的行為或屬性時,可以考慮使用 Abstract Class 。
當類別有共同的操作介面,但是實作上卻有所差異時,可以考慮使用 Interface 。
不過當我們發現整個類別體系用錯 Abstract Class 或 Interface 時也不用過於煩惱,這時「 Refactoring (重構) 」就是我們會需要的好幫手。更詳細的 Refactoring 說明可以參考以下書籍:
Refactoring by Martin Fowler (中譯本:重構 by 侯捷、熊節)
Refactoring To Patterns by Joshua Kerievsky
Network traffic analysis can be a vital part of the software debugging and testing process. This tutorial will teach you how to monitor all incoming and
Tutorials\
Android SDK
\Rating:
1
2
3
4
5
Analyzing Android Network Traffic
Maria Garcia Cerdeno on May 9th 2012 with 6 Comments
Tutorial Details
Technology: Android + Wireshark
Difficulty: Intermediate
Completion Time: 30 - 45 Minutes
DownloadSOURCE FILES
Network traffic analysis can be a vital part of the software debugging and testing process. This tutorial will teach you how to monitor all incoming and outgoing traffic on an Android device in order to better debug your applications!
As a developer, one often has to build software that performs HTTP requests, sends messages, or grabs information from incoming or outgoing requests over the network. When these network transactions work from the very beginning, all is good; we are receiving exactly what is expected and what we are sending is proper formatted and with the correct values.
However, this frequently does not happen, and one needs to understand exactly what is being sent and received over the network in order to determine what has gone wrong. Who knows, maybe the request is not even being made and we are not aware of it! This is a circumstance in which knowing how to capture and analyze the network traffic becomes crucial.
Capturing network traffic for later analysis is good, but it’s even better if we are able to perform this analysis at the same time the capture is taking place. By doing so, one can know which request or response corresponds to each use case, thus making the analysis much easier. In the following steps, I will show you how to capture real time traffic from an Android device and pipe it to a network analyzer like Wireshark.
Step 1: Installing tcpdump
The first step is to install tcpdump on the device. tcpdump is a command-line utility that captures the traffic on a particular network device and dumps it to the filesystem. tcpdump can be downloaded from here.
Once the tcpdump binary has been downloaded, all we need to do is use adb to push the file onto the device. To be able to do so, your handset needs to be connected to and properly identified by your computer.
First things first, it is important that you update your path adding Android’s SDK platform-tools directory to it if you haven’t yet. In case you have never done it, there are clear instructions on how to do so on theandroid developers page. Ready? Open a terminal and type the following:
1
adb devices
The connected device should show up in a list. If this is not the case, make sure that it is correctly connected and that you have all the drivers needed for that specific handset.
See the device on the list? Great! We are now ready to push the tcpdump file onto it:
1
adb push /home/tcpdump /data/local
To perform the next few steps we need to gain root privileges on the device and make sure that tcpdump is executable:
1
2
3
4
adb shell
cd data/local
su
chmod 777 tcpdump
Step 2: Saving the Traffic Dump to File
Tcpdump can now be started from the same adb shell and the output saved to a file:
1
./tcpdump -s 0 -v -w out.pcap
The complete list of tcpdump options can be found in the man page of tcpdump.
Once the dump is completed, we can stop capturing the data. In order to do so, you simply need to press Ctrl+C. The resulting file can be pulled out of the device and saved locally, so that it can get analyzed usingWireshark.
1
adb pull /data/local/out.pcap /home/out.pcap
But this is not exactly what we wanted, is it? What we want is to be able to pipe it to Wireshark in real time! Relax, we are getting there.
Step 3: Piping Network Traffic to a Port
The process of capturing the network packets is basically the same in this case. However, instead of writing the datagrams to a file, we want to write them to the standard output, so that we can then redirect them using netcat to a specific port on the handset.
In order to do so, the tcpdump command has to change slightly:
1
adb shell "./data/local/tcpdump -n -s 0 -w - | nc -l -p 12345"
The traffic is now being redirected to the port 12345 in the handset.
Step 4: Installing Netcat
Before going any further, lets make sure that you have netcat installed, as we are going to need it. Type nc in a new console, hit enter and look at what happens. Do you get the standard message explaining how to use the command? Awesome, you are good to go. Skip the rest of this section and keep going!
Still reading? Well, I guess that means you do not have netcat installed after all. Do not panic, you can download it from here for Windows.
Step 5: Piping Traffic to Wireshark
Remember what we mentioned earlier regarding updating the path so that adb would be available? You want to do that with netcat and Wireshark as well.
Once this is done, we can use adb‘s forward option, which will forward the packets from the tcp port 12345 in the device to the tcp port 54321 on the PC. We will again use netcat to grab those incoming packets coming in through port 54321, and pipe them to Wireshark.
This is done in the following command, typed in a new console:
1
adb forward tcp:12345 tcp:54321 && nc 127.0.0.1 54321 | wireshark -k -S -i -
Note that the number of the port chosen is irrelevant. The only reason why different numbers have been chosen is to show how the different commands connect to each other. The same port number could have been used for both commands (or different numbers from the above, as long as the ports are not being used!) and then they would work just the same.
You need to make sure that Wireshark runs with the correct permissions. Otherwise, even when Wiresharkgets opened, a popup will show up informing you of an exception.
Step 6: Making Life Easier
Once the different utilities have been set up, the process of capturing the network traffic and piping it intoWireshark is done through two commands, simultaneously running in two different terminals:
1
2
adb shell "./data/local/tcpdump -n -s 0 -w - | nc -l -p 12345"
adb forward tcp:12345 tcp:54321 && nc 127.0.0.1 54321 | wireshark -k -S -i -
Now, this process is still pretty manual. One has to manually open two terminals and type all those instructions, making sure nothing is left behind for this to work. This is a nuisance. Well, that problem is easily solved by putting these instructions onto a script, so that it does all the work for us.
Windows users can automate the process using the script in the download file attached to this post.
1
2
start adb shell "./data/local/tcpdump -n -s 0 -w - | nc -l -p 12345"
adb forward tcp:12345 tcp:54321 && nc 127.0.0.1 54321 | wireshark -k -S -i -
Notes for Mac Users
If you’ve been following this tutorial on a Mac, you are probably scratching your head, thinking why the above process does not really seem to be working for you. There are a couple of reasons why this might be the case. Let’s try to fix that.
First of all, make sure that you are using the right path of Wireshark! This might seem trivial, but is is not. You do not want to use the path to the app, but the whole path to the actual Wireshark executable (e.g. “/Applications/Wireshark.app/Contents/Resources/bin/wireshark”).
Fixed? Good! Just a couple more things to go. When invoking Wireshark through the command line, we are using a minus sign at the end. This represents the standard input and in Windows it will work just fine. However, this will not work on a Mac. Luckily, this can be substituted with the name of a pipe. You want to specify 2 (corresponding to lo0) as the pipe to use. Besides, you might need to grant super user permissions in order to be able to execute Wireshark. This is the resulting command that you want to use:
1
adb forward tcp:12345 tcp:54321 && nc 127.0.0.1 54321 | sudo wireshark -k -S -i 2
This is the perl script that will work for Mac users (it is also attached as a download to this post):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/perl
# Perform adb command on shell
# to check if the device is attached
$netstat = `adb shell 'netstat' 2>&1`;
if($netstat =~ m/error: device not found/)
{
die("Plug in your phone!\n");
}
# Gain root priviledges
open(SUDO, "|sudo echo ''");
close(SUDO);
# Redirect STDERR output to STDOUT
open STDERR, '>&STDOUT';
# Perform tcpdump and nc in background
open(COMMAND1, "(adb shell \"data/local/tcpdump -n -s 0 -w - | nc -l -p 12345\") |");
# Perform piping to wireshark
open(COMMAND2, "((adb forward tcp:12345 tcp:54321 && nc 127.0.0.1 54321 | sudo wireshark -k -S -i 2) &) 2>&1 > /dev/null |");
# Make sure the exit message appears after wireshark has been launched (hacky)
sleep(5);
print("Press ctrl-c to exit...");
<STDIN>;
The following two packages will allow you to utilize loading-after-the-fact (external loading of spritesheet png files) once the game/starling framework has started.
Please send any feedback or updates as I haven't added some necessary features (such as garbage collection once a scene has been switched). Also, there could be an easier way to do this but I haven't found it yet.
//useage for starting the loading //"Africa" refers to the 'scene' or set of spritesheets to load (see the assets class) //the function name passed is a function (in the calling class) to be called when the entire set of spritesheets has loaded. Assets.loadAssets("Africa", loadingCompleteStartGame); function loadingCompleteStartGame():void{ trace("loading scene complete!"); //start game here!!! }
package { import starling.textures.Texture; import flash.utils.Dictionary; import flash.display.Bitmap; import starling.textures.TextureAtlas; public class Assets { //the embedded sprite sheet used for anything we need at runtime (before loading the others - like a menu) [Embed(source="images/sprite-sheet-embedded.png")] public static const Sprite_sheet_embedded:Class; [Embed(source="images/sprite-sheet-embedded.xml", mimeType="application/octet-stream")] public static const Sprite_sheet_embedded_xml:Class; private static var gameTextures:Dictionary = new Dictionary(); private static var gameTextureAtlas:Dictionary = new Dictionary(); private static var counter:int = 0; private static var completedCall:Function; public static function getAtlas(name:String = "Sprite_sheet_embedded"):TextureAtlas { if(gameTextureAtlas[name] == undefined && name == "Sprite_sheet_embedded"){ trace("LOADING MISSING INDEX IN GAMETEXTUREATLAS[NAME] " + name); var texture:Texture = getTexture(name); var xml:XML = XML(new Assets[name + "_xml"]()); gameTextureAtlas[name] = new TextureAtlas(texture, xml); } return gameTextureAtlas[name]; } public static function getTexture(name:String):Texture { if(gameTextures[name] == undefined){ var bitmap:Bitmap = new Assets[name](); gameTextures[name] = Texture.fromBitmap(bitmap); } return gameTextures[name]; } public static function loadAssets(Set:String, Func:Function):void{ completedCall = Func; //for loading in multiple 'scenes' in a game if(Set == "Africa"){ //load all the africa spritesheets var africa1:AssetsLoader = new AssetsLoader("Africa_1", "africa-1", completedFunction); africa1.start(); var africa2:AssetsLoader = new AssetsLoader("Africa_2", "africa-2", completedFunction); africa2.start(); } else { //load an other sheet trace("NO OTHER SPRITE SHEETS TO LOAD!"); } } private static function completedFunction(name:String, xml:XML, bitmap:Bitmap):void { counter++; //add the xml and bitmap to the dictionary object as needed var texture:Texture = Texture.fromBitmap(bitmap); gameTextureAtlas[name] = new TextureAtlas(texture, xml); if(counter >= 2){ trace("completed loading ALL asset images/xml"); completedCall(); } } } }
And the asset loader class the above references
package { import flash.display.Loader; import flash.events.Event; import flash.events.IOErrorEvent; import flash.events.UncaughtErrorEvent; import flash.events.ProgressEvent; import flash.net.URLLoader; import flash.net.URLRequest; import flash.display.Bitmap; import flash.events.ErrorEvent; public class AssetsLoader { private var url:String = ""; private var id:String = ""; private var loader:Loader; private var completeFunc:Function; private var completeCounter:int = 0; private var xml:XML; private var loadedBitmap:Bitmap; public function AssetsLoader(Name:String, URl:String, Func:Function):void { loader = new Loader(); url = URl; id = Name; completeFunc = Func; } public function start():void { // create the loader for the png // when texture is loaded loader.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, imageUncaughtErrors); loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, imageProgressEvents); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageComplete); // load the texture loader.load(new URLRequest("http://google.com/images/sprites/" + url + ".png")); // create the loader for the xml file paired with the sprites var xmlloader:URLLoader = new URLLoader(); xmlloader.addEventListener(Event.COMPLETE, xmlComplete); xmlloader.addEventListener(IOErrorEvent.IO_ERROR, xmlErrorEvent); xmlloader.load(new URLRequest("http://google.com/images/sprites/" + url + ".xml")); } private function xmlComplete(event:Event):void { trace(id + " xml load complete"); xml = new XML(event.target.data); checkLoadingComplete(); } private function xmlErrorEvent(event:IOErrorEvent):void { trace(id + " error loading xml file"); } private function imageComplete(event:Event):void { trace(id + " image load complete"); // use the loaded image and add it to the dictionary loadedBitmap = event.currentTarget.loader.content as Bitmap; //gameTextures[id] = loadedBitmap; checkLoadingComplete(); } private function imageUncaughtErrors(event:UncaughtErrorEvent):void { //we'll need to try again possibly or tell the user of the complete and utter failure! trace(id + " things went completely wrong!"); if (event.error is Error) { var error:Error = event.error as Error; // do something with the error trace(id + " error message: " + error.message); } else if (event.error is ErrorEvent) { var errorEvent:ErrorEvent = event.error as ErrorEvent; // do something with the error trace(id + " error event"); } else { // a non-Error, non-ErrorEvent type was thrown and uncaught trace(id + " unknown or other error, we really should stop and access our life choices"); } } private function imageProgressEvents(event:ProgressEvent):void { var prog:int = Math.ceil(event.bytesLoaded / event.bytesTotal * 100); trace(id + " progress: " + prog + "%"); } private function checkLoadingComplete():void { completeCounter++; if(completeCounter >= 2){ trace(id + " completed"); //call a custom function when loading completes! completeFunc(id, xml, loadedBitmap); } } } }
POSTED 7 MONTHS AGO #
Hemanth Sharma's personal website for technology blogging and app development experiments
è½æ¥å¨æ¨¡å¼(Adapter Pattern)
以下程式碼範例來自於Head First Design Pattern一書!
轉接器故名思義,在真實世界中,我們常常會看到,像是三孔轉兩孔的電源插頭、不同國家電壓切換的旅行用轉接頭。
透過轉接器的轉換,就可以讓不同的裝置取得電力或是資訊!就像這樣!
那麼,在物件導向的轉接器是什麼呢?
假如我們有一套軟體系統,希望和其他廠商即有的程式庫搭配使用,但是這個新廠商所設計出來的介面,不同於舊廠商的介面。
這兩個介面無法匹配,所以無法運作!!
你一定不會想改變既有的程式碼來解決這個問題,特別是之前講的,當需求一變動,我們就要翻修一些我們既有的系統,這樣非常的不靈活。
而我們也無法改變廠商的程式碼。
轉接器類別就此誔生!我們可以寫一個類別,將新廠商介面轉接成我們所期盼的介面吧!
轉接器實踐了我們所希望的介面,而且也能和廠商的介面溝通!
這個轉接器運作起來就是一個中介人,它將客戶發出的請求轉換成廠商類別所看的懂的請求!
這個原理很淺顯易懂!
因此當你未來,看到一個含有包裝鏡頭盒的鏡頭
這個東西,看起來就是一隻高檔的長焦鏡頭,而且也有Canon的品牌標籤呢
該有的開關跟焦段刻度都有呢…
那麼…他必定可能是一隻Canon的鏡頭具備鏡頭外觀介面轉接器的………………………杯子…
好了,回歸正題,同理可證,如果有一個東西朝你走過來,它走起路來像一隻企鵝,叫起來像一隻企鵝,那麼他必定仍然可能只是一隻具備企鵝轉接器的…鴨子:
那麼這個名叫鴨子轉接器的轉接器到底是怎麼運作的呢?
這一次,企鵝實踐了以下介面,具備企鵝叫以及企鵝走路的能力了。
1: public interface Penguins
2: {
3: void Penguin_gobble(); //咯咯叫
4: void Penguin_walk();
5: }
國王企鵝是企鵝的次類別!
1: public class KingPenguins:Penguins //國王企鵝
2: {
3: public void Penguin_gobble()
4: {
5: Console.WriteLine("企鵝叫");
6: }
7:
8: public void Penguin_walk()
9: {
10: Console.WriteLine("企鵝走路");
11: }
12: }
而鴨子的介面呢?
1: public interface Duck
2: {
3: void Duck_quack(); //嗄嗄叫
4: void Duck_walk();
5: }
綠頭鴨是鴨子的介面的一個具象實踐!
1: public class MallardDuck:Duck //綠頭鴨
2: {
3: public void Duck_quack()
4: {
5: Console.WriteLine("鴨子叫");
6: }
7:
8: public void Duck_walk()
9: {
10: Console.WriteLine("鴨子走路");
11: }
12: }
因此,假如我們目前動物園中因為企鵝生病了,為了讓遊客看到企鵝,園方想用一些鴨子物件來充數的話,因為介面設計的不同,所以不能公然拿來用…。
那麼只好寫一個轉接器了:
1: public class DuckAdapter : Penguins
2: {
3: Duck gDuck;
4:
5: public DuckAdapter(Duck pDuck)
6: {
7: this.gDuck = pDuck;
8: }
9:
10: #region Penguins 成員
11: public void Penguin_gobble()
12: {
13: gDuck.Duck_quack(); //因為都是叫,所以直接調用Duck中的方法,就很簡單了!
14: Console.Write("壓低聲音!\n"); //
15: }
16:
17: public void Penguin_walk()
18: {
19: gDuck.Duck_walk();
20: Console.Write("翅膀向下伸值,左右搖擺!\n"); //
21: }
22:
23: #endregion
24: }
這個轉接器我們要先實踐我們希望轉換成的類別,我們是動物園的企鵝期望被看到,所以我們是實現一個鴨子轉接器,來轉換成企鵝的樣子!
在當中的建構式中,我們要取得被轉換者的參考,也就是取得要充數成企鵝的鴨子。
而明確實作企鵝類別中,我們發現要像企鵝的話,鴨子的叫聲要壓低聲音,然後走路的樣子要模仿企鵝搖擺搖擺!
最後我們只需要一些程式碼來測試我們的轉接器
1: static void Main(string[] args)
2: {
3: //先看看一隻正版的企鵝
4: KingPenguins penguin = new KingPenguins();
5: MallardDuck duck = new MallardDuck(); //要充數成企鵝的鴨子!
6:
7: Penguins duckAdapter = new DuckAdapter(duck); //叫鴨子穿上企鵝套裝(轉接器)
8: Console.Write("\n\n鴨子展示:\n"); //先看看正版鴨子
9: duck.Duck_quack();
10: duck.Duck_walk();
11:
12: //我們以下建立了一個企鵝展示台
13: Console.WriteLine("\n\n國王企鵝展示:");
14: testPenguin(penguin);
15:
16: Console.WriteLine("\n\n假裝是企鵝的鴨子展示:");
17: testPenguin(duckAdapter);
18:
19: Console.ReadKey();
20: }
上述測試程式的重點就是,我們透過鴨子轉接器來假裝成企鵝的樣子,而我們實作了一個TestPenguin的方法,我們傳入了宣告為penguin的鴨子轉接器的物件。
鴨子轉接器中則實作了要表現的像企鵝一樣的方法。
測試的結果如下:
現在我們已經知道什麼是轉接器了!
其轉接器的模式如下:
這個模式可以讓客戶和被轉接者之間是鬆綁的,他們並不認識彼此,而客戶接收到呼叫的結果的時候,並未察覺這一切是透過一個轉接器中介傳導。
這個轉接器的方法,似乎也是省不了多少程式碼的撰寫!不過,幸好的是,相形之下,這個轉接器模式提供了一個轉接器類別,將所有的改變封裝在一個類別中。
比起更改客戶端的程式來呼叫新的介面,這個模式是比較好的做法!
真實世界中的轉接器模式的定義如下:
將一個類別的介面,轉換成另一個介面以供客戶使用。轉接器讓原本介面不相容的類別可以合作。
類別圖如下:
HeadFirst Design Pattern後記:
轉接器分成了”物件轉接器”以及”類別轉接器”,上圖是物件轉接器,若要實踐類別轉接器的話,就需要多重繼承,然而在C#跟Java中都不支援
若後續在多重繼承的語言中,仍然有可能會實作到(且看下一篇)。另一個問題是轉接器只能封裝一個類別嗎?不見得,範例總是最單純的環境狀況,在下下一篇
我們會看到一些情況,需要讓一個轉接器包裝多個被轉接者。也就會涉及下一個設計模式:表象模式(Facade Pattern),就靜待分曉吧。
最後這個轉接器模式充滿著良好的00設計守則:透過使用物件合成,以修改的介面包裝被轉接者,這種做法可以達到讓被轉接者的任何次類別,都可以搭配使用轉接器。最後提醒這個模式是如何讓客戶和介面之間建立關係,而不是讓客戶和實踐的內容建立關係。我們可以使用數個轉接器,每個一個都負責轉換不同組的終端類別。
或是像本例中,加入新的實踐內容,只要遵守目標介面就可以囉。
Web design resources - web safe colours / colors. Includes rgb and hex values for html and css.
Web-Safe Colours
The diagram and table below identify the 216 web-safe, or browser-safe, colours. These are the only colours that can be displayed reliably across all browsers and operating systems. (i.e. the colours will not dither or band when used to display areas of flat colour).
Web-safe diagram
For a more detailed view of the following diagram, see the web-safe colours diagram.
Web-safe table
To view a colour in more detail, click the colour's hex value in the third column and the background will change to that colour. You can then see how other colours appear in relation to that colour.
To return to a white background, just click the refresh button on your browser.
Colour NameColHexRGB ABCDEFabcdef1234567890 #FF00FF2550255ABCDEFabcdef1234567890 #FF33FF25551255ABCDEFabcdef1234567890 #CC00CC2040204ABCDEFabcdef1234567890 #FF66FF255102255ABCDEFabcdef1234567890 #CC33CC20451204ABCDEFabcdef1234567890 #9900991530153ABCDEFabcdef1234567890 #FF99FF255153255ABCDEFabcdef1234567890 #CC66CC204102204ABCDEFabcdef1234567890 #99339915351153ABCDEFabcdef1234567890 #6600661020102ABCDEFabcdef1234567890 #FFCCFF255204255ABCDEFabcdef1234567890 #CC99CC204153204ABCDEFabcdef1234567890 #996699153102153ABCDEFabcdef1234567890 #66336610251102ABCDEFabcdef1234567890 #33003351051 ABCDEFabcdef1234567890 #CC00FF2040255ABCDEFabcdef1234567890 #CC33FF20451255ABCDEFabcdef1234567890 #9900CC1530204ABCDEFabcdef1234567890 #CC66FF204102255ABCDEFabcdef1234567890 #9933CC15351204ABCDEFabcdef1234567890 #6600991020153ABCDEFabcdef1234567890 #CC99FF204153255ABCDEFabcdef1234567890 #9966CC153102204ABCDEFabcdef1234567890 #66339910251153ABCDEFabcdef1234567890 #330066510102 ABCDEFabcdef1234567890 #9900FF1530255ABCDEFabcdef1234567890 #9933FF15351255ABCDEFabcdef1234567890 #6600CC1020204ABCDEFabcdef1234567890 #9966FF153102255ABCDEFabcdef1234567890 #6633CC10251204ABCDEFabcdef1234567890 #330099510153 ABCDEFabcdef1234567890 #6600FF1020255ABCDEFabcdef1234567890 #6633FF10251255ABCDEFabcdef1234567890 #3300CC510204 ABCDEFabcdef1234567890 #3300FF510255 ABCDEFabcdef1234567890 #0000FF00255ABCDEFabcdef1234567890 #3333FF5151255ABCDEFabcdef1234567890 #0000CC00204ABCDEFabcdef1234567890 #6666FF102102255ABCDEFabcdef1234567890 #3333CC5151204ABCDEFabcdef1234567890 #00009900153ABCDEFabcdef1234567890 #9999FF153153255ABCDEFabcdef1234567890 #6666CC102102204ABCDEFabcdef1234567890 #3333995151153ABCDEFabcdef1234567890 #00006600102ABCDEFabcdef1234567890 #CCCCFF204204255ABCDEFabcdef1234567890 #9999CC153153204ABCDEFabcdef1234567890 #666699102102153ABCDEFabcdef1234567890 #3333665151102ABCDEFabcdef1234567890 #0000330051 ABCDEFabcdef1234567890 #0033FF051255 ABCDEFabcdef1234567890 #3366FF51102255ABCDEFabcdef1234567890 #0033CC051204ABCDEFabcdef1234567890 #0066FF0102255 ABCDEFabcdef1234567890 #6699FF102153255ABCDEFabcdef1234567890 #3366CC51102204ABCDEFabcdef1234567890 #003399051153ABCDEFabcdef1234567890 #3399FF51153255ABCDEFabcdef1234567890 #0066CC0102204ABCDEFabcdef1234567890 #0099FF0153255 ABCDEFabcdef1234567890 #99CCFF153204255ABCDEFabcdef1234567890 #6699CC102153204ABCDEFabcdef1234567890 #33669951102153ABCDEFabcdef1234567890 #003366051102ABCDEFabcdef1234567890 #66CCFF102204255ABCDEFabcdef1234567890 #3399CC51153204ABCDEFabcdef1234567890 #0066990102153ABCDEFabcdef1234567890 #33CCFF51204255ABCDEFabcdef1234567890 #0099CC0153204ABCDEFabcdef1234567890 #00CCFF0204255 ABCDEFabcdef1234567890 #00FFFF0255255ABCDEFabcdef1234567890 #33FFFF51255255ABCDEFabcdef1234567890 #00CCCC0204204ABCDEFabcdef1234567890 #66FFFF102255255ABCDEFabcdef1234567890 #33CCCC51204204ABCDEFabcdef1234567890 #0099990153153ABCDEFabcdef1234567890 #99FFFF153255255ABCDEFabcdef1234567890 #66CCCC102204204ABCDEFabcdef1234567890 #33999951153153ABCDEFabcdef1234567890 #0066660102102ABCDEFabcdef1234567890 #CCFFFF204255255ABCDEFabcdef1234567890 #99CCCC153204204ABCDEFabcdef1234567890 #669999102153153ABCDEFabcdef1234567890 #33666651102102ABCDEFabcdef1234567890 #00333305151 ABCDEFabcdef1234567890 #00FFCC0255204ABCDEFabcdef1234567890 #33FFCC51255204ABCDEFabcdef1234567890 #00CC990204153ABCDEFabcdef1234567890 #66FFCC102255204ABCDEFabcdef1234567890 #33CC9951204153ABCDEFabcdef1234567890 #0099660153102ABCDEFabcdef1234567890 #99FFCC153255204ABCDEFabcdef1234567890 #66CC99102204153ABCDEFabcdef1234567890 #33996651153102ABCDEFabcdef1234567890 #006633010251 ABCDEFabcdef1234567890 #00FF990255153ABCDEFabcdef1234567890 #33FF9951255153ABCDEFabcdef1234567890 #00CC660204102ABCDEFabcdef1234567890 #66FF99102255153ABCDEFabcdef1234567890 #33CC6651204102ABCDEFabcdef1234567890 #009933015351 ABCDEFabcdef1234567890 #00FF660255102ABCDEFabcdef1234567890 #33FF6651255102ABCDEFabcdef1234567890 #00CC33020451 ABCDEFabcdef1234567890 #00FF33025551 ABCDEFabcdef1234567890 #00FF0002550ABCDEFabcdef1234567890 #33FF335125551ABCDEFabcdef1234567890 #00CC0002040ABCDEFabcdef1234567890 #66FF66102255102ABCDEFabcdef1234567890 #33CC335120451ABCDEFabcdef1234567890 #00990001530ABCDEFabcdef1234567890 #99FF99153255153ABCDEFabcdef1234567890 #66CC66102204102ABCDEFabcdef1234567890 #3399335115351ABCDEFabcdef1234567890 #00660001020ABCDEFabcdef1234567890 #CCFFCC204255204ABCDEFabcdef1234567890 #99CC99153204153ABCDEFabcdef1234567890 #669966102153102ABCDEFabcdef1234567890 #3366335110251ABCDEFabcdef1234567890 #0033000510 ABCDEFabcdef1234567890 #33FF00512550 ABCDEFabcdef1234567890 #66FF3310225551ABCDEFabcdef1234567890 #33CC00512040ABCDEFabcdef1234567890 #66FF001022550 ABCDEFabcdef1234567890 #99FF66153255102ABCDEFabcdef1234567890 #66CC3310220451ABCDEFabcdef1234567890 #339900511530ABCDEFabcdef1234567890 #99FF3315325551ABCDEFabcdef1234567890 #66CC001022040ABCDEFabcdef1234567890 #99FF001532550 ABCDEFabcdef1234567890 #CCFF99204255153ABCDEFabcdef1234567890 #99CC66153204102ABCDEFabcdef1234567890 #66993310215351ABCDEFabcdef1234567890 #336600511020ABCDEFabcdef1234567890 #CCFF66204255102ABCDEFabcdef1234567890 #99CC3315320451ABCDEFabcdef1234567890 #6699001021530ABCDEFabcdef1234567890 #CCFF3320425551ABCDEFabcdef1234567890 #99CC001532040ABCDEFabcdef1234567890 #CCFF002042550 ABCDEFabcdef1234567890 #FFFF002552550ABCDEFabcdef1234567890 #FFFF3325525551ABCDEFabcdef1234567890 #CCCC002042040ABCDEFabcdef1234567890 #FFFF66255255102ABCDEFabcdef1234567890 #CCCC3320420451ABCDEFabcdef1234567890 #9999001531530ABCDEFabcdef1234567890 #FFFF99255255153ABCDEFabcdef1234567890 #CCCC66204204102ABCDEFabcdef1234567890 #99993315315351ABCDEFabcdef1234567890 #6666001021020ABCDEFabcdef1234567890 #FFFFCC255255204ABCDEFabcdef1234567890 #CCCC99204204153ABCDEFabcdef1234567890 #999966153153102ABCDEFabcdef1234567890 #66663310210251ABCDEFabcdef1234567890 #33330051510 ABCDEFabcdef1234567890 #FFCC002552040ABCDEFabcdef1234567890 #FFCC3325520451ABCDEFabcdef1234567890 #CC99002041530ABCDEFabcdef1234567890 #FFCC66255204102ABCDEFabcdef1234567890 #CC993320415351ABCDEFabcdef1234567890 #9966001531020ABCDEFabcdef1234567890 #FFCC99255204153ABCDEFabcdef1234567890 #CC9966204153102ABCDEFabcdef1234567890 #99663315310251ABCDEFabcdef1234567890 #663300102510 ABCDEFabcdef1234567890 #FF99002551530ABCDEFabcdef1234567890 #FF993325515351ABCDEFabcdef1234567890 #CC66002041020ABCDEFabcdef1234567890 #FF9966255153102ABCDEFabcdef1234567890 #CC663320410251ABCDEFabcdef1234567890 #993300153510 ABCDEFabcdef1234567890 #FF66002551020ABCDEFabcdef1234567890 #FF663325510251ABCDEFabcdef1234567890 #CC3300204510 ABCDEFabcdef1234567890 #FF3300255510 ABCDEFabcdef1234567890 #FF000025500ABCDEFabcdef1234567890 #FF33332555151ABCDEFabcdef1234567890 #CC000020400ABCDEFabcdef1234567890 #FF6666255102102ABCDEFabcdef1234567890 #CC33332045151ABCDEFabcdef1234567890 #99000015300ABCDEFabcdef1234567890 #FF9999255153153ABCDEFabcdef1234567890 #CC6666204102102ABCDEFabcdef1234567890 #9933331535151ABCDEFabcdef1234567890 #66000010200ABCDEFabcdef1234567890 #FFCCCC255204204ABCDEFabcdef1234567890 #CC9999204153153ABCDEFabcdef1234567890 #996666153102102ABCDEFabcdef1234567890 #6633331025151ABCDEFabcdef1234567890 #3300005100 ABCDEFabcdef1234567890 #FF0033255051 ABCDEFabcdef1234567890 #FF336625551102ABCDEFabcdef1234567890 #CC0033204051ABCDEFabcdef1234567890 #FF00662550102 ABCDEFabcdef1234567890 #FF6699255102153ABCDEFabcdef1234567890 #CC336620451102ABCDEFabcdef1234567890 #990033153051ABCDEFabcdef1234567890 #FF339925551153ABCDEFabcdef1234567890 #CC00662040102ABCDEFabcdef1234567890 #FF00992550153 ABCDEFabcdef1234567890 #FF99CC255153204ABCDEFabcdef1234567890 #CC6699204102153ABCDEFabcdef1234567890 #99336615351102ABCDEFabcdef1234567890 #660033102051ABCDEFabcdef1234567890 #FF66CC255102204ABCDEFabcdef1234567890 #CC339920451153ABCDEFabcdef1234567890 #9900661530102ABCDEFabcdef1234567890 #FF33CC25551204ABCDEFabcdef1234567890 #CC00992040153ABCDEFabcdef1234567890 #FF00CC2550204 ABCDEFabcdef1234567890 #FFFFFF255255255ABCDEFabcdef1234567890 #CCCCCC204204204ABCDEFabcdef1234567890 #999999153153153ABCDEFabcdef1234567890 #666666102102102ABCDEFabcdef1234567890 #333333515151ABCDEFabcdef1234567890 #000000000
My previous post explained and provided a very simple method for extracting colours from a BitmapData image, by averaging the colours in specific areas. This can have several applications, for example it features in a large amount of prototypes for the update to my Motion Tracking engine. However, if you want to create an accurate and [...]