Wednesday, February 1, 2017

[Android] Một số thành phần chính trong lập trình android


Hôm nay, mình sẽ giới thiệu đến các thành phần chính của một ứng dụng Android.

  1. Activity: Là thành phần tối quan trọng trong Android. Được xem là một màn hình tương tác với người dùng. Một activity sẽ chưa một file giao diện để chứa fragment hay view khác
  2. Service: Là thành phần chạy nền với ứng dụng và trong suốt với người dùng nhằm thực hiện một công việc nào đó. VD: Chơi nhạc, cảnh báo, cập nhật dữ liệu, gọi service…
  3. Broadcast Reveiver: Là thành phần luôn chạy ngầm trong hệ thống android với mục đích thu nhập thông tin từ hệ điều hành hay từ ứng dụng. VD: Bắt một sms gửi đến, % pin, có cuộc gọi…
  4. Content provider: cho phép tập trung dữ liệu ở một nơi và các ứng dụng khác nhau sẽ truy xuất vào nó khi cần thiết. 
I. Về Activity:
  • Activity BackStack tuân theo quy tắc LIFO (Last In First Out) như hình vẽ:

  • Vòng đời (lifecycle) của một Activity:
  1. onCreate(): Phương thức callback này được gọi khi ứng dụng mới start, nhưng chưa có thể tương tác với người dùng. Ở trong phương thức này chúng ta thường sử dụng để setContentView(), khởi tạo cái view, inflate view từ xml đăng kí event cho view, khởi tạo Adapter cho ListView, RecyclerView…
  2. onStart(): Phương thức callback này được gọi ngay sau khi onCreate() được gọi. Ở phương thức này chúng ta vẫn chưa tương tác được với người dùng trên UI.
  3. onResume(): Phương thức này được gọi ngay sau khi onStart() được gọi. Ở phương thức này chúng ta có thể tương tác được với UI.
  4. onPause(): Phương thức callback này được sử dụng khá phổ biến trong vòng đời của Activity. Chúng ta thường lưu lại trạng thái của các biến trong method này.
  5. onStop(): Phương thức callback này có thể được gọi ngay sau khi phương thức onPause được gọi. Phương thức này được gọi khi chúng ta nhấn nút home app.
  6. onRestart(): Phương thức callback này gọi khi activity đã stoped, gọi trước khi bắt đầu start lại Activity.
  7. onDestroy(): Phương thức này đợc gọi khi chúng ta nhấn back từ activity, hoặc call method finish() của activity.

II. Về Fragment: 

  • Là một phần giao diện người dùng. Được đặt trong activity. 
  • Cho phép thiết kế linh hoạt, có tính tái sử dụng cao, kết hợp nhiều fragment để thiết kế một giao diện. 
  • Tương tự như Activity, fragment cũng có vòng đời, các sự kiện đầu vào và có thể thêm hoặc gỡ bỏ trong quá trình runtime.











III. Service: 
  1. Một dịch vụ (Service) là một thành phần chạy ngầm bên trên hệ điều hành để thực hiện các hoạt động dài hạn mà không cần phải tương tác với người sử dụng và nó hoạt động ngay cả khi ứng dụng bị phá hủy.
IV. Broadcast Reveiver:
  1. Broadcast Receiver phản hồi các thông báo phát ra từ các ứng dụng khác hoặc từ chính hệ thống. Những thông báo này đôi khi được gọi là các event hoặc intent. Ví dụ, các ứng dụng cũng có thể khởi tạo các tín hiệu broadcast để thông báo cho ứng dụng khác biết rằng một số dữ liệu đã được về tới thiết vị và là có sẵn cho chúng để sử dụng, vì thế Broadcast Receiver thông dịch thông tin đó và khởi tạo hành động thích hợp.
  2. Ví dụ:
  • Trạng thái của Wifi, Bluetooth.
  • Có tin nhắn sms, gọi điện
  • Máy đã khởi động xong
  • Trạng thái màn hình của điện thoại



V. Content provider
  1. Content providers là thành phần cung cấp dữ liệu từ một ứng dụng đến một ứng dụng khác dựa trên các Request. Mỗi Request được xử lý bằng các phương thức của class ContentResolver. Một Content Provider có thể sử dụng các cách lưu trữ dữ liệu khác nhau, dữ liệu có thể được lưu trữ trong databases, file,  hoặc thông qua Network.
  2. Content Providers cho phép bạn tập trung dữ liệu ở một nơi và các ứng dụng khác nhau sẽ truy xuất vào nó khi cần thiết. Content Provider hoạt động rất giống với một cơ sở dữ liệu, và bạn có thể truy vấn nó, chỉnh sửa nội dung, cũng như là thêm xóa các nội dung sử dụng các phương thức: insert(), update(), delete(), query().
VI. Một số các thành phần khác:
  1. Toast: Là kiểu hiển thị thông báo lên trên màn hình trong một khoảng thời thời gian ngắn.
  2. Dialog: Là một hộp thoại hiển thị cho phép người dùng thực hiện một công việc, nhiệm vụ. Dùng trong các trường hợp cần show confirm hoặc chọn một giá trị nào đó.
  3. Widget: Là một tiện ích nhỏ thường được đặt trên home screen. Nó rất tiện dụng bởi nó cho phép người dùng đặt các ứng dụng yêu thích của họ lên home screen và truy cập sử dụng chúng một cách nhanh chóng. Ví dụ như các widget tồn tại sẵn như widget về music, thời tiết, đồng hồ, báo thức,....
  4. Notification: Hiện thị một thông báo từ ứng dụng lên trình thông báo của điện thoại. Nó sẽ không tự mất như Toast mà người dùng phải tự thực hiện action hoặc xóa để notification mất đi
  5. Intent: Một Intent trong Android là một miêu tả trừu tượng của một hoạt động để được thực hiện. Nó có thể được sử dụng với startActivity để chạy một Activity, broadcastIntent để gửi nó tới bất kỳ thành phần BroadcastReceiver nào quan tâm đến, và với startService(Intent)hoặc bindService(Intent, ServiceConnection, int) để giao tiếp với một Service ở Background.
  6. Intent – Filter: IntentFilter là thành phần giúp cho hệ thống Android biết được ứng dụng của bạn có thể làm được những gì.
  7. Manifest: Mỗi ứng dụng đều cần có AndroidManifest.xml để mô tả những thông tin quan trọng của nó cho hệ thống Android. File này sẽ khai báo ứng dụng cần quyền gì, có những activity nào, chạy service gì, có khai báo Broadcast nào không….
  8. Listview: là một extends của ViewGroup. Dùng để hiển thị một danh sách các Elements.
  9. RecycleView: về chức năng thì tương tự như ListView giúp tùy biến cách hiển thị dẽ dàng hơn, sử dụng ViewHolder Design Pattern để tái sử dụng tài nguyên…
  10. Viewpaper: Sử dụng Gesture thực hiện khi người dùng thực hiện xong thao tác.
  11. Adapter: Là một đối tượng đóng vai trò như cầu nối giữa AdapterView và dữ liệu thật
  12. LinearLayout, RelativeLayout: Là một extends của ViewGroup, dùng để chứa các view khác. Với Linear các View sẽ được sắp xếp theo 1 chiều ngang hoặc dọc với các tỉ lệ xác định.
  13. Toolbar, ActionBar: Thanh tiêu đề của ứng dụng Android cho phép chúng ta thao tác nhanh, tiện lợi hơn.
Hy vọng với bài viết này, các bạn có thể nắm được các thành phần của một ứng dụng android. Mọi ý kiến các bạn để lại comment nhé.

Tuesday, January 17, 2017

[Java] Giới thiệu về Generic và Annotation

Chào các bạn, hôm nay mình sẽ giới thiệu về kỹ thuật Generic và Annotation trong java.
Cả hai kỹ thuật này đều được thêm vào từ Java 5.

Generic

  1. Về generic:
    1. Là một feature được thêm vào từ Java 5.0 
    2. Generic thể hiện tính trừu tượng trong Java, bản thân generic cũng có thể kế thừa hoặc được kế thùa từ một kiểu dử liệu khác. 
    3. Generic mô tả một cách trừu tượng class sẽ được sử dụng trong class hay method. 
    4. Mục đích của nó: Cung cấp tính an toàn về kiểu trong thời điểm biên dịch. 
    5. Generic được sử dụng trong: Class Generic, Method Generic,Interface Generic.
  2. Generic giúp giải quyết?

    1. Giúp bộ dịch xác minh được kiểu dữ liệu. 
    2. Bộ dịch sẽ biết chính xác cần phải ép kiểu thể nào.
Annotation:
  1. Một số bài toán:
    1. Bài toán của Hibernate: đây là một frame làm việc với database thông qua việc mapping object. Từ Java Bean phải mapping qua bảng tương ứng với database. Sau đó hibernate sẽ chuyển thành các câu lệnh SQL tương ứng và thực thi. Nhưng không phải lúc nào các trường này được ánh xạ chính xác với database nên ta phải mô tả code. 
    2. Trước khi annatotion ra đời, để biểu diễn meta data cho một class, property, method developer phải sử dụng XML, Properties, Comment. Đến java 5 Sun thêm vào cái gọi là annotation.
  2. Annotation là gì:
    1. Là một feature được thêm vào từ Java 5.0
    2. Là một dạng meta data đặc ta cho một đối tượng hoặc một method hay là một property mà bạn có thể thêm vào Java Code. 
    3. Mục đích:
      1. Chỉ dẫn cho trình compiler 
      2. Chỉ dẫn Build-time 
      3. Chỉ dẫn trong thời điểm Runtime.
  3. Annatotion: chỉ dẫn cho trình compiler?
    1. Java cung cấp sẵn một số annotation thường gặp như: 
      1. @Override 
      2. @Deprecated 
      3. @SuppressWarnings
      4. @SafeVarargs 
      5. @Documented. 
    2. Để tự tạo ra các chỉ dẫn để trình compiler có thể hiểu được thì sử dụng Annotation processing tool. (APT)
  4. Annatotion: chỉ dẫn Build-time?
    1. Annotation được sử dụng trong lúc build-time để tạo ra các mã nguồn, biên dịch mã nguồn, tạo ra các file XML. Xây dụng các tool tự động. 
    2. Ví dụ như tool Hiberate: đọc database sẽ tự động build thành các class, xml tương ứng.
    3. Thông thường sau khi biên dịch thì các annotations không có mặt trong mã Java. Tuy nhiên vẫn có thể sử dụng reflection để đọc các annotations lúc run-time. 
    4. Để làm việc nay thì thiết lập như sau: 
      1. @Retention(RetentionPolicy.RUNTIME)
Đây là 2 kỹ thuật nâng cao của Java mà bất kỹ Senior Java nào cũng phải biết. 
Hy vọng với bài viết này bạn sẽ có thể hình dung tổng quát và hiểu được khái niệm Generic và Annotation cũng như trường hợp sử dụng chúng.
Với bài viết sau, tôi sẽ có bài toán cũng như ví dụ cụ thể về 2 kỹ thuật này.

Sunday, January 15, 2017

[Swift] Sử dụng NSUserDefaults để lưu dữ liệu


Một bộ nhớ ứng dụng được tạo ra để lưu trữ dữ liệu trong ứng dụng. Điều đó có nghĩa là khi xóa ứng dụng thì bộ nhớ này sẽ mất đi. Nó được gọi là NSUserDefaults, NSUserDefaults  có thể lưu trữ các kiểu dữ liệu integers, booleans, strings, arrays, dictionaries, dates...

Nhưng hãy cần thận, nếu bạn lưu trữ quá nhiều dữ liệu sẽ ảnh hưởng đến tốc độ khi bật ứng dụng.

Để sử dụng NSUserDefaults làm như sau

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(25, forKey: "Age")
defaults.setBool(true, forKey: "Gender")
defaults.setObject("Paul Hudson", forKey: "Name")
defaults.setObject(NSDate(), forKey: "LastRun")

Dữ liệu được lưu vào NSUserDefaults không bị mất đi khi bạn thoát ứng dụng.

Để lấy dữ liệu đã lưu trong NSUserDefaults ta làm như sau:

let defaults = NSUserDefaults.standardUserDefaults()
let age = defaults.integerForKey("Age")
let gender= defaults.boolForKey("Gender")
let name= defaults.objectForKey("Name")

[Design Pattern] Singleton trong java và swift


Mẫu thiết kế singleton:
Nó là gì?
Mẫu thiết kế singleton đảm bảo chỉ duy nhất môt thực thể của một class được tạo ra và nó sẽ cung cấp cho bạn một phương thức để truy cập đến thực thế đó.
Kiểm soát việc tạo ra các thực thể nhưng có thể lấy ra thực thế.
Dùng nó trong trường hợp nào?
Khi bạn tạo ra một class mà bạn chỉ muốn chỉ có duy nhất một thực thể là thể hiện của class đó và bạn có thể truy cập đến nó ở bất kỳ nơi đâu khi bạn muốn.
Ví dụ như : Khi bạn tạo ra một class làm việc với file, config ,class lưu collection dùng chung, hoặc database . Bản chỉ cần duy nhất một thực thể của class đó và bạn sẽ sử dụng nó ở bất kỳ nơi đâu.
Dùng nó như thế nào?
Đầu tiên tôi tạo ra một class với tên là Database. Để không class nào có thể khỏi tạo nó (đảm bảo duy nhất có một thực thể) tôi sẽ private contructor của class trên.
  1. In Java
  2. public class Database{
  3.     private Database();
  4. }
  5. In Swift
  6. class Database{
  7.     private init();
  8. }
Và tạo một thuộc tính có tên là INSTANCE có kiểu Database  và một phương trả về thuộc tính đó. Để các class khác có thể sử dụng phương thức này, tôi thêm từ khóa static để biến phương thức này thành phương thức của lớp.
  1. In Java
  2. private Database INSTANCE;
  3. public static Database getInstance(){
  4.    if(INSTANCE == null){
  5.       INSTANCE = new Database();
  6.    }
  7.    return INSTANCE;
  8. }
  9. In Swift
  10. var Database sharedInstance;
  11. class func getInstance() -> Database { 
  12.    if(sharedInstance == nil) { 
  13.       sharedInstance = Database() 
  14.    } 
  15.    return sharedInstance 
  16. }
Như trên tôi kiểm tra xem INSTANCE có bằng null hay không. Nếu bằng null thì tôi tạo một đối tượng. Và trả về INSTANCE.
Có một vấn đề xảy ra. Nếu có hai luồng (thread) chạy song song và thực hiện hàm if thì sẽ có 2 thực thể được tạo ra. Để tránh trường hợp này mình thêm từ khóa synchronized. Khi hàm getInstance đã được chạy thì bất kỳ các luồng khác phải đợi hàm này chạy xong mới gọi được.

  1. public static synchronized Database getInstance(){
  2.    if(INSTANCE == null){
  3.      INSTANCE = new Database();
  4.    }
  5.    return INSTANCE;
  6. }
Ok đến đây đã khá ổn nhưng sử dụng từ khóa synchronized đồng nghĩa với việc các luồng có thể phải đợi chờ lâu vì phải đợi luồng đang gọi hạm getInstance chạy xong mới gọi được. Để tránh trường hợp này, tôi sẽ tạo 1 thực thể của lớp Database ngày khi class này được sử dụng, và sử dụng từ khóa final để ngăn không cho thay đổi đối tượng mà INSTANCE trỏ đến  :

  1. In Java:
  2. private static final Database INSTANCE = new Database();
  3. In Swift
  4. static let sharedInstance = Database()
Lúc này hàm getInstance sẽ trả về đối tượng INSTANCE:
  1. In Java:
  2. public static Database getInstance(){
  3.    return INSTANCE;
  4. }
  5. In Swift
  6. class func getInstance() -> Database { 
  7.    return sharedInstance 
  8. }
Để truy cập đến thực thể của class Database bạn thực hiện : Database.getInstance() lúc này trả về 1 thực thể có kiểu Database.
Với swift ta làm như sau:

OK ! Đến đây bạn có thể chắc chắn rằng sẽ chỉ có duy nhất một thực thể của class Database được tạo ra và bạn có thể sử dụng hàm getInstance để truy cập vào thực thế đó. Việc còn lại là bạn viết các phương thức, các setter, getter cho nó. Đây chính là mẫu thiết kế singleton.

[Android] Ẩn bàn phím khi start activity (fragment)


Để ẩn bàn phím khi start một activity hoặc add fragment ta làm như sau:
Cách 1: Trong file AndroidManifest.xml add dòng sau vào activity mà bạn muốn

android:windowSoftInputMode="stateHidden"
Cách 2: Trong file giao diện xml thêm dòng sau vào view cha của editext

android:focusable="true"
android:focusableInTouchMode="true"

Done.

Thursday, January 5, 2017

Java Core - Enum Types


Enum là một kiểu dữ liệu đặc biệt, nó cho phép chứa tập hợp các biến hay còn gọi là kiểu dữ liệu liệt kê. Vậy tại sao lại có kiểu dữ liệu enum và nó sẽ giúp chúng ta như thế nào.
Mình sẽ lấy vị dụ như sau : Trong game thường có các vật phẩm tăng gold hay exp sau mỗi màn đánh. Mình định nghĩa một enum như sau :

  1. public enum EffectItem {
  2. EXP,GOLD;
  3. }
Ok vậy là ta có có một tập hợp các hiệu ứng khi sử dụng vật phẩm là tăng gold và exp. Nhưng ta vẫn chưa định nghĩa tăng bao nhiêu cả.Ta làm như sau:

  1. public enum EffectItem {
  2. EXP(20),GOLD(30);
  3.         private int value;// khai báo một biến value.

  4. EffectItem(int value) { //một contructor với tham số value
  5. this.value = value;
  6. }

  7. public int getValue() {//hàm lấy ra giá trị value
  8. return this.value;
  9. }
  10. }
Nhìn có vẻ đây là một class thực sự với thuộc tính value và contructor với đầu vào int. Còn dòng 2 như các thực thể được khởi tạo vơi các giá trị cụ thể 20,30.

Một vấn đề nữa, tôi muốn với mỗi giá trị của item ta sẽ có một mô tả tương ứng. Ta làm như sau:
  1. public enum EffectItem {
  2. EXP(20),GOLD(30);
  3.         private int value;// khai báo một biến value.

  4. EffectItem(int value) { //một contructor với tham số value
  5. this.value = value;
  6. }

  7. public int getValue() {//hàm lấy ra giá trị value
  8. return this.value;
  9. }
  10.         
  11.         public String getString() {// với mỗi giá trị của enum sẽ có mô tả tương ứng.
  12. switch (this) {
  13. case EXP:
  14. return "Tang EXP 20%";
  15. case GOLD:
  16. return "Tang EXP 30%";
  17. default:
  18. return "";
  19. }
  20. }
  21. }

Đến đây ta đã cơ bản tạo xong một enum. Vậy sử dụng nó như thế nào?
 - Vì enum là một kiểu dữ liệu vì vậy ta khai báo một thuộc tính của class cần dùng như sau:

  1. public class Item {
  2. private String name;
  3. private EffectItem effect;

  4. public Item(EffectItem effect) {
  5. this.effect = effect;
  6. }

  7. public String getName() {
  8. return name;
  9. }

  10. public void setName(String name) {
  11. this.name = name;
  12. }

  13. public EffectItem getEffect() {
  14. return effect;
  15. }

  16. public void setEffect(EffectItem effect) {
  17. this.effect = effect;
  18. }
  19. }
Sử dụng phương thức effect.getValue() để lấy ra giá trị của enum và  effect.getString() để có được mô tả.
Ngoài ra, bản thân enum có một class mô tả nó với các phương thức và thuộc tính. Ví dụ như:  values() : trả về tập 1 mảng chứa cả các giá trị của enum. Ta có thể dùng vòng foreach để duyệt.

Done. Mong bài viết sẽ có ích với các bạn :D

Thursday, November 24, 2016

Design Pattern - Adapter

Tiếp tục với mẫu thiết kế adapter.

Nó là gì?
 Mẫu adapter chuyển đổi giao diện thành một giao diện khác mà phù hợp với yêu cầu. Giúp kết nối các lớp có giao diện không tương thích để làm việc với nhau

Dùng nó trong trường hợp nào?.
Khi ta muốn chuyển đổi một lớp với một giao diện thành giao diện mà ta mong muốn.
Xậy dựng, mở rộng các phương thức của lớp có sẵn phù hợp với yêu cầu.
Tái sử dụng giao diện cũ. Giảm thiểu việc viết lại mã lệnh.

Dùng nó như thế nào?

Tình Huống:

   Thực tế : Có một công ty muốn mỏ rông công ty bằng cách chuyển địa điểm làm việc. Khi chuyển địa điểm thì có thêm các cơ sở mới.
   Trong Java : giả sử ta đã có lớp với phương thức có sẵn để hiển thị 1 chuồi như sau ra màn hình: void ShowName (String str) với chuỗi đã được chuẩn hóa nhưng chương trình mới yêu cầu ta phải hiển thị một danh sách các chuỗi được chuẩn hóa với giao diện mới. 

- Xử lí tình huống : 

   Tình huống 1) Có người để xuất ý kiến ta sẽ mua toàn bộ các cơ sở vật chất đề phù hợp với môi trường mới. Nhưng có một đề xuất khác là ta sẽ sử dụng lại các công cụ có sẵn của công từ và từ đó sẽ thêm các cơ sở vật chất mới phù hợp.
   Tình huống 2)  Một lập trình viên đề xuất , ta sẽ tạo một lớp hoàn toàn mới để ghi 1 danh sách chuỗi với phương thức để chuẩn hóa. Nhưng không, một lập trình viên khác nêu ý kiến: “Tôi có một giải pháp, tôi sẽ sử dụng mẫu chuyển đổi Adapter để tạo một lớp phù hợp từ lớp có sẵn”. 

Tạo mẫu Adapter đầu tiên :
Đầu tiên lớp có sẵn của ta được mô tả với  1 interface:
  1. public interface IShowName { 
  2.    void showName(String name); 
  3. }
Và một lớp thực thi interface trên :
  1. public class ShowName implements IShowName{
  2.    @Override public void showName(String name){   
  3.       System.out.println(this.standardize(name));
  4.    }
  5.    public String standardize(String name){
  6.       String resuilt = name.trim();
  7.       return name;
  8.    }
  9. }
Và một interface mô tả phương thức phù hợp với chương trình của ta :
  1. public interface IShowListName {
  2.    void showListName(List listName);
  3. }

Và một lớp thực thi interface :
  1. public class ShowListNameAdapter implements IShowListName{
  2.       private ShowName shownName;
  3.       public ShowListNameAdapter(ShowName shownName) {
  4.          this.shownName = shownName;
  5.          }
  6.       @Override
  7.       public void showListName(List listName) {
  8.          for (String name : listName) {
  9.          shownName.showName(name);
  10.       }
  11.    }
  12. }
Thử chạy mẫu Adapter:

  1. public class TestAdapter {
  2.    public static void main(String[] args) {
  3.       ArrayList array = new ArrayList<>();
  4.       array.add(" Teo ");
  5.       array.add(" Ti ");
  6.       array.add(" Ku ");
  7.       IShowListName adapter = new ShowListNameAdapter(new ShowName());    
  8.       adapter.showListName(array); 
  9.    }
  10. }
Kết quả chương trình sẽ hiển thị “Teo”, ”Ti”, “Ku” đã được chuẩn hóa.
Đây chỉ là một ví dụ nhỏ của Adapter pattern. Hy vọng bạn sẽ sớm có cái nhìn tổng quát và hiểu rõ thêm về Adapter pattern.

Tuesday, November 15, 2016

Design Pattern - Proxy


Nó là gì?
 - Mẫu Proxy (người đại diện) đại diện cho 1 chức năng của lớp khác. Bạn có thể hiểu, ta thuê 1 luật sư về đại diện cho ta, người luật sư này có thể dùng các quyền của mình một cách gián tiếp để nói cho các người khác một cách chính xác vì luật sư am hiểu về pháp luật hơn mình.

Khi nào dùng nó?

 - Khi bạn muốn bảo vệ quyền truy xuất vào các chức năng (phương thức) của thực thể.
 - Bổ sung trước khi thực hiện phương thức của thực thể.
 - Tạo đối tượng với chức năng được nâng cao theo yêu cầu.

Dùng nó như thế nào?

 Tôi sẽ xây dựng một ví dụ đơn giản như sau:
- Tôi có 1 inteface mô tả chức năng của một class :


  1. public interface ReadFile { 
  2.      public String readFile(); 
  3. }
}

Tiếp theo tạo class User triển khai interface trên:

  1. public class User implements ReadFile{
  2.       private String name; //Tên của người dùng 
  3.       public User(String name) { 
  4.            this.name = name; 
  5.       } @Override public String readFile() { //Phương thức đọc file            return name + "readed"; 
  6.       } 
  7.  }

Và một class Proxy đại diện cho lớp User:
  1. public class UserProxy implements ReadFile{ 
  2.       private ReadFile instance; 
  3.       private String name; 
  4.       public UserProxy (String name){ 
  5.            this.name = name; 
  6.       } 
  7.       @Override 
  8.        public String readFile() { 
  9.             if(name.equals("ok")){ //nêu tên người dùng là ok thì mới thực hiện phương thức của lớp User, không thì báo lỗi!                           if(instance ==null){ 
  10.                     instance = new User(name); 
  11.                   }
  12.                 return instance.readFile(); 
  13.             } 
  14.           return "You can't read file"; 
  15.         } 
  16.  }


Thử chạy chương trình test như sau :
  1. public class Main {
  2.     public static void main(String[] args) { 
  3.         UserProxy user1 = new UserProxy("ok");
  4.         System.out.println(user1.readFile());
  5.         UserProxy user2 = new UserProxy("hello"); 
  6.         System.out.println(user2.readFile()); 
  7.      } 
  8. }


Kết quả :
ok readed
You can't read file

Trên chỉ là một ví dụ nhỏ về proxy, nó còn có rất nhiều cách dùng khác. Hy vọng bạn có thể nắm bắt được các mẫu thiết kế pattern bởi nó thực sự cần thiết đối với một lập trình viên.

Monday, July 18, 2016

Refactoring - Tái cấu trúc mã nguồn - Giới thiệu

Hôm nay mình xin giới thiệu một "kỹ thuật" khá quan trọng là Refactoring. Vậy nó là gì ?

- Theo mình hiểu thì Refactoring là tái cấu trúc, tổ chức lại mã nguồn mà không làm thay đổi hành vi của nó. Bạn có thể hình dung, phần mềm của mình là 1 căn phòng ngủ, refactoring có nghĩa là trang trí, thay đổi vị trí của các đồ dùng trong phòng ngủ để nó đẹp hơn, thoải mái hơn nhưng bản chất nó vẫn là phòng ngủ chứ không phải là phòng khách hay phòng bếp.


+ Vậy tại sao bạn nên refactoring? 

- Nó giúp cải thiện cấu trúc thiết kế phần mềm của bạn.
- Giúp mã nguồn của bạn dễ hiểu hơn.
- Nó giúp bạn có thể tìm thấy nguyên nhân dẽ dàng hơn khi phần mềm của bạn dính lỗi.
- Ngoài ra nó giúp bạn viết phần mềm nhanh hơn.


+ Khi nào mình nên  refactoring ?

- Khi bạn cần thêm một funciton.
- Khi bạn cần sửa một lỗi xuất hiện trong phần mềm.
- Và khi bạn review lại mã nguồn.


+ Khi nào bạn không nên refactoring ?

- Khi mã nguồn của bạn phải làm việc hầu như là chính xác trước khi bạn refactoring. Nếu mã nguồn của bạn chưa hoạt động chính xác hoặc chưa chạy được. Bạn không nên refactoring.
- Khi phần mềm của bạn đã đến deadline.

+ Một số vấn đề với refactoring :
- Khi bạn làm việc với database: Khi phần mềm của bạn làm việc với db, nó đã có một quan hệ chặt chẽ với db. Việc sử dụng refactoring làm bạn phải thay đổi cấu trúc của DB.
- Thay đổi interface : khi bạn đã public interface của bạn, việc tái cấu trúc lại nó cũng là một vấn đề.
- Khi bạn thay đổi thiết kế, việc refactoring gặp rất nhiều khó khăn, hầu như bạn phải đập và viết lại mới.

+ Vậy mã nguồn như thế nào là mã nguồn chưa tốt, cần refactoring ? 

- Có rất nhiều cách nhận biết mã nguồn của bạn chưa tốt (bẩn hay "bóc mùi"), sau đây là một số cách nhận biết cơ bản :
      - Duplicated Code : code của bạn có sự trùng lặp, khi có một đoạn mã với chức năng giống hệt được viết tại 2 nơi khác nhau.
      - Long Method : phương thức của bạn quá dài - tính theo số dòng code.
      - Large Class : Khi class của bạn chứa các phương thức và thuộc tính của như một class khác. Lấy một ví dụ : bạn có một class làm việc với DB nhưng class đó lại chứa những phương thức cũng như thuộc tính của class hiển thị View cho người dùng.
      - Long Parameter List : Khi phương thức của bạn có quá nhiều tham số.
      - Primitive Obsession : Khi bạn dùng các kiểu nguyên thủy để đại diện cho thực thể. Ví dụ bạn có một danh sách người chơi, bạn dùng các 1 mảng các con số như 1, 2, 3 để đại diện cho các người chơi, như vậy bạn đã mắc lỗi này.
      - Switch Statements : Bạn nên cần thần khi làm việc với các câu lệnh switch. Bơi nó là nơi rất dẽ xuất hiện code "bẩn".

+ Hy vọng qua bài viết này bạn sẽ có cái nhìn khái quán về refactoring . Bài viết dựa trên slide của thầy Nguyễn Ngọc Tú .  Download slide tại : http://www.mediafire.com/?7s55au5tp3kwfch
   

Tuesday, June 7, 2016

J2EE - Basic component of struts 2

- Các component chủ yếu của Struts 2 bao gồm :
     - Action : là component của server, là tầng gọi tất cả các xử lí logic, bussiness để xử lí request của người dùng. Và nó sẽ tương tác trực tiếp với các model, cũng như cung cấp dữ liệu cho View.
     - Interceptor : Interceptor tương tự như servlet filter. Interceptor được gọi trước khi action được gọi và sau khi action xử lí xong.
     - The value stack : là nơi chứa tất cả các thông tin cần thiết.
     - The OGNL : The object graph navigation language, giúp lấy dữ liệu từ value stack. Ngoài ra nó còn giúp chuyển đổi và truyền dữ liệu.
     - Validation : cung cấp khả năng validation các dữ liệu.

Monday, June 6, 2016

J2EE - Design Pattern MVC

Là mẫu thiết kế ứng dụng theo 3 tầng : View - Model - Controller. Mỗi phần có một chức năng, nhiệm vụ riêng biệt với các phần khác.

- Tại sau cần phải tách ứng dụng của mình thành 3 phần ?
     - Thứ nhất : làm như vật sẽ dẽ dàng trong công việc quản lí code. Bởi các thành phần này tách biệt lẫn nhau. Sự ràng buộc của nó rất ít. 
     - Thức hai : dẽ dàng nâng cấp, bảo trì.Bởi vì các thành phần MVC là các thành phần đọc lập và mỗi thành phần đảm nhiệm một chức năng, cũng như nhiệm vụ riêng biệt.

- Thành phần trong MVC : như tên gọi của nó thì ta có 3 thành phần:
     - View : là tầng hiển thị các component tương tác với người dùng. Tức và phần giao diện mà người dùng có thể nhìn thấy.
     - Model : là tầng chứa bussiness, logic của ứng dụng. 
     - Controller : nhiệm vụ điều hướng các yêu cầu của người dùng tương ứng với các model.

- MVC làm việc như thế nào ?
     - Đầu tiên thông qua View, người dùng sẽ gửi 1 request lên server. Và yêu cầu này sẽ được gửi đến Controller.

     - Tiếp theo controller sẽ chuyển dữ liệu của request vào model. Và model sẽ xử lí và truyền dữ liệu lên View.

     - Sau khi view đã có dữ liệu từ model. Nó sẽ transforms thành các output tương ứng. Và cuối cũng trả về response cho người dùng.

Sunday, June 5, 2016

J2EE - Giới thiệu tổng quan về Framework Struts 2

- Đầu tiên mình xin nói qua một chút khái niệm cũng như đặc điểm của một framework :
     - Framework là một tập hợp của các interface và các class giúp phát triển một ứng dụng.
     - Một framework cung cấp cách phương thức sử dụng ở nhiều trường hợp khác nhau.
     - Vai trò của một framework, framework cung cấp sẵn các công cụ, các phương thức cho một công việc nào đó cụ thể.
     - Đặc điểm của một framework :
           - Dễ dàng cho việc nâng cấp và bảo trì.
           - Có khả năng mở rộng và dẽ sử dụng.
           - Cho phép tái sử dụng code.

- Tiếp theo mình sẽ giới thiệu struts 2:
      - Struts 2 : là một open resource được phát triển với Craig McClanahan và được hỗ trợ The Apache Software Foundation.
       - Struts 2 : là một framework theo mô hình MVC. Dựa trên Struts 1 và là cải thiện của struts 1. Struts 2 việc định nghĩa các thành phần trở nên đơn gian và sáng sủa hơn.
       - Mô hình làm việc của Struts 2 :

     - Trong struts 2 là chỉ bao gồm 1 controller và controller này có thể chứa các controller khác.
     - Sau khi nhận request của người dùng, controller sẽ xác định xem sẽ gọi đến Action nào.Sau đó dữ liệu truyền vào model.
     - Sau đó Action sẽ chuyển hướng đến View và View sẽ lấy dữ liệu từ model và trả về response cho người dùng.
     - Mô hình chi tiết hơn :

          - Khi người dùng có 1 request lên server. Thì request sẽ chuyển đến ActionMapper và sau đó nó sẽ đi qua các filter.
           - Sau đó nó sẽ đọc file struts.xml, tùy thuộc vào config trong file struts.xml. ActionProxy sẽ chuyển đến Action tương ứng. Trước khi gọi Action thì nó sẽ các gọi các interceptor nếu có. Sau đó nó gọi đến Action thật sự và nó trả về resuilt.
          - Sau khi có Resuilt nó sẽ định hướng đến View, sau đó nó tiếp tục đi qua các interceptor và trả về Response cho người dùng.

Tuesday, December 1, 2015

[Java] Clone Object trong Java

Trong nhiều trường hợp ta muốn clone object ra một object tương ứng để giúp chúng ta thao tác trên object mà không làm ảnh hưởng đến object gốc.

Trong java việc này ra đơn giản. Để clone một object ta implement Cloneable như trong ví dụ sau.
public class Employee implements Cloneable {
private String EmployeeID;
private String FullName;
public Employee() {
}
public String getEmployeeID() {
return EmployeeID;
}
public void setEmployeeID(String employeeID) {
EmployeeID = employeeID;
}
public String getFullName() {
return FullName;
}
public void setFullName(String fullName) {
FullName = fullName;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Sử dụng như sau:
Employee employee = new Employee();
employee.setFullName("Đức");
try {
Employee employeeClone = (Employee) employee.clone();
employeeClone.setFullName("Đức cloned");
employee.getFullName(); // trả về Đức
employeeClone.getFullName(); // trả về Đức cloned
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
OK vậy ta đã tạo được object clone. Nhưng với các object phức tạo như chứa các list con, trong list con lại còn list con bé hơn nữa. Với các object phức tạp như thế này thì đòi hỏi các object con phải implements Cloneable và for để tạo ra các object clone. Sử dụng cách này rất mất công và tốn time (chưa xét hiệu năng).
Và cách mà em đưa ra là tận dụng thư viện GSon để clone object. Như ví dụ trên để tạo Object Clone em làm như sau:
Employee employee = new Employee();
employee.setFullNam
c");
Gson gson = ne
n();
String jsonObject = gson.toJson(e
ee);
Employee employeeCloned = gson.fromJson(jsonObject, Employe
ss);
employeeCloned.getFullName();
Với cách này ta sẽ được một Object cloned với toàn bộ các property một cách đơn giản và nhanh chóng.
Download thư viện gson tại https://github.com/google/gson

Monday, May 4, 2015

HƯỚNG DẪN TẠO VB SERVICE JSON:

B1:
 Tạo project như sau.

B2:
Mở file IService trong thư mục App_Code và thêm dòng
Class IService:

[ServiceContract]
public interface IService
{

[OperationContract]
    [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json,BodyStyle=WebMessageBodyStyle.WrappedRequest)]
MyService.Service1.Persion GetData(int value);

[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);

// TODO: Add your service operations here
}

// Use a data contract as illustrated in the sample below to add composite types to service operations.
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";

[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}

[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}


Class Service:


namespace MyService
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
    public class Service1 : IService1
    {
        public Persion GetData(int value)
        {
            return new Persion() {
            ID=5,Name=""};
        }

        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }
        public class Persion {
            public int ID { get;set;}
            public String Name { get; set; }
        }
    }
}

B3:
Tiếp theo là đến mục config cho service.
<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior>
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>  
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <services>
      <service name="MyService.Service1">
        <endpoint binding="webHttpBinding" contract="MyService.IService1"></endpoint>
      </service>
    </services>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

B4:
Test Service. Cài đặt restclient cho FireFox.
Download bản cài đặt tại : https://addons.mozilla.org/vi/firefox/addon/restclient/
Bặt firefox vào mục tools -> Add-ons -> Install Add-on from file.

Kết quả sau khi test.