2013-02-19 37 views
5

Tôi đang phát triển ứng dụng thị giác máy tính và tôi sẽ cần lớp Trình phân loại. Lớp này sẽ không thay đổi cho mỗi lần chạy ứng dụng và nó tải dữ liệu được đào tạo từ đĩa khi khởi tạo. Tôi muốn đảm bảo rằng toàn bộ chương trình sẽ có quyền truy cập vào cùng một dữ liệu được đào tạo và tôi muốn chặn tải lại từ đĩa sau khi chúng được tải.Lớp Singleton với tham số

Điều tôi đang xem xét là sử dụng lớp tĩnh hoặc singleton. Tôi không chắc chắn làm thế nào để tải dữ liệu vào lớp tĩnh, bởi vì đường dẫn đến tập tin dữ liệu không biết tại thời gian biên dịch - nó sẽ là đối số chương trình. Vì vậy, tôi đã suy nghĩ về mô hình Singleton, nhưng ở đó tôi không biết làm thế nào để khởi tạo nó một cách năng động.

Ý tưởng của tôi là sử dụng sau đây:

class Singleton { 
    private static Singleton instance; 
    private Singleton() { ... } 
    private static SomeDataObject data; 

    public static Singleton getInstance() { 
     if(instance == null) 
      instance = new Singleton(); 

      return instance; 
    } 

    public static init(string dataPath){ 
     if(data == null) 
      loadDataFromFile(dataPath) 
    } 
} 

này sẽ không hoạt động , bởi vì tôi đã không kiểm soát mà phương pháp sẽ được gọi đầu tiên.

Tôi biết cách thích hợp là tạo cá thể với dữ liệu ngay từ đầu và chuyển nó cho tất cả các lớp và phương pháp cần nó, nhưng đó không phải là giải pháp tổng quát. Tôi có thể theo dõi tất cả các cuộc gọi đến Phân loại trong mã của riêng tôi, nhưng nếu tôi làm cho mã như API, điều này sẽ là một vấn đề.

Tóm lại cách khởi tạo singleton khi chạy?

+0

Đối số chương trình 'dataPath' có thể truy cập được bằng cách nào? –

+0

Bạn không cần *** cả *** đối tượng dữ liệu đơn lẻ *** và ***. Ngoài ra, thực hiện singleton hiện tại của bạn không phải là chủ đề an toàn. – Perception

+0

@MattBall nó có thể là từ GUI, hoặc đối số dòng lệnh – jnovacho

Trả lời

8

Tôi không nghĩ (chính xác) những gì bạn muốn làm sẽ hoạt động.

dưới đây sẽ làm việc:

public static void main(String[] args) 
{ 
    Singleton.init("somepath"); 
    ... 
    Singleton.getInstance().doingStuff(); 
    ... 
} 

Một thực hiện tốt hơn có thể là: (mà sẽ gây ra một NullPointerException nếu bạn cố gắng sử dụng nó mà không gọi init đầu tiên) (không thực sự Singleton bất kỳ mặc dù hơn)

private static Singleton instance; 
private SomeDataObject data; 

private Singleton(String path) { loadDataFromFile(path); ... } 

public static Singleton getInstance() { 
    return instance; 
} 

public static void init(String dataPath){ 
    instance = new Singleton(dataPath); 
} 

Sau đó có: (có thể thực hành mã hóa xấu sang một bên)

class Main 
{ 
    public static void main(String[] args) 
    { 
    Singleton.currentPath = "somepath"; 
    ... 
    } 
} 

class Singleton 
{ 
    public static String currentPath = null; 
    private static Singleton instance; 
    private SomeDataObject data; 

    private Singleton(String path) { loadDataFromFile(path); ... } 

    public static Singleton getInstance() { 
    if(instance == null && currentPath != null) 
     instance = new Singleton(currentPath); 
    return instance; 
    } 
} 

mà tôi cho rằng không thực sự giải quyết được nhiều.

+0

Nhưng tôi cũng có thể làm Singleton.getInstance(). DoStuff() và đó sẽ là lỗi, vì không khởi tạo đã được thực hiện. Như tôi đã nói trong bài viết của mình, trong mã của tôi, tôi có thể theo dõi điều này, nhưng nói chung điều này không giải quyết được gì. – jnovacho

+0

@jnovacho Bạn có thể có hàm tạo đọc một biến tĩnh được lưu trữ ở một nơi khác, nhưng tôi cho rằng đây là cơ bản cùng một vấn đề. Tôi không nghĩ rằng bạn có thể làm tốt hơn những gì tôi cung cấp trong câu trả lời (trừ khi bạn muốn vượt qua đường dẫn trên mỗi cuộc gọi đến 'getInstance'). – Dukeling

+0

cho tôi lần đầu tiên làm việc với public static void init() –

0

Tôi sử dụng thứ gì đó "an toàn hơn" so với giải pháp chiến thắng hiện tại với hầu như không đồng bộ được sử dụng.

import java.util.function.Supplier; 

public class InitOnce { 

/** 
* Marked as final to prevent JIT reordering 
*/ 
private final Supplier<String> theArgs; 

private InitOnce(Supplier<String> supplier) { 
    super(); 
    this.theArgs = supplier; 
} 

/** 
* Uses the arguments to do something 
* 
* @return 
*/ 
public String doSomething() { 
    return "Something : " + theArgs.get(); 
} 

/** 
* Initializes all the things 
* 
* @param someArgs 
*/ 
public static synchronized void init(final Supplier<String> someArgs) { 
    class InitOnceFactory implements Supplier<InitOnce> { 
     private final InitOnce initOnceInstance = new InitOnce(someArgs); 

     @Override 
     public InitOnce get() { 
      return initOnceInstance; 
     } 
    } 

    if (!InitOnceFactory.class.isInstance(instance)) { 
     instance = new InitOnceFactory(); 
    } else { 
     throw new IllegalStateException("Already Initialized"); 
    } 
} 

private static Supplier<InitOnce> instance = new InitOnceHolder(); 

/** 
* Temp Placeholder supplier 
* 
*/ 
private static final class InitOnceHolder implements Supplier<InitOnce> { 
    @Override 
    public synchronized InitOnce get() { 

     if (InitOnceHolder.class.isInstance(instance)) 
      throw new IllegalStateException("Not Initialized"); 

     return instance.get(); 
    } 

} 

/** 
* Returns the instance 
* 
* @return 
*/ 
public static final InitOnce getInstance() { 
    return instance.get(); 
} 
}