首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

一路关于单例模式的题

2013-09-07 
一道关于单例模式的题本帖最后由 daituzhang 于 2013-09-05 07:37:33 编辑我是java零基础者,靠google和bai

一道关于单例模式的题
本帖最后由 daituzhang 于 2013-09-05 07:37:33 编辑 我是java零基础者,靠google和baidu在解这道题,如果有低级错误望各位大神抽打
因为题目原文是英文,我翻译可能有点不准确:

1)建立一个叫做Organization的类,它不能被实例化超过一次但是可以提供给全局。它包含仅一个叫做getMembers 的public method,返回一个collection.
2) 建立另一个叫做Member的类,publicly exposes(公共得包括?) FirstName, lastName 和 DateJoined bean properties,请使用合适的数据类型
3)建立第三个叫做OrganizationHelper的类,包含一个method用于输出Organization类中所有Members的数据。输出的类型随意。

然后我就开始纠结了,第一小题我百度下来应该是个单例模式的问题,collection我觉着有点像c++里面的containers,我就用了ArrayList.但是这个ArrayList到底怎么获取member的信息我却想不清楚。然后因为根据单例模式,这个类必须向整个系统提供这个实例对象,那么要怎么同时又返回一个collection呢?还是说这个实例对象本身就是一个collection?所以我两个method就分开了,只有getMember设成了public

第二小题我又纠结什么是bean property,百度到javaBean但是好像是和html结合起来用的,我是不是对bean property这两个单词过度理解了?

第三小题我只是放了打印的代码……但是那个method名字叫XXhelper,C++面向对象里面helper函数是在类外面的,我不清楚java是不是也有这种区别,所以我就只做了个把它作为像main一样的class了

代码如下,虽然得到了结果,但是我很怀疑错过了几个关键的点


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date; 
import java.util.List;

class Organization {
  ArrayList<Member> List = new ArrayList<Member>();  
  void add(Member temp)
  {
  List.add(temp);   
  }
  private static Organization instance=null;
  private Organization(){}
  static Organization getInstance(){
      if(instance==null)
      instance=new Organization();
      return instance;
  }
  public ArrayList<Member> getMembers()
  {
  return List;
  }
  
}

class Member                              
{                                                               
 public String firstName;                                     
 public String lastName;                                      


 public Date DateJoined;                                             
                                         
public void set( String firstName, String lastName, Date DateJoined)           
{                                                                                                                         
    this.firstName = firstName;          
    this.lastName = lastName;            
    this.DateJoined = new Date( DateJoined.getTime() ); 
 }                                                                                                                         
                                                            
 public String getFirstName()
 {
  return this.firstName;


 }
 public String getLastName()
 {
  return this.lastName;
 }
 public Date getDateJoined()                      
 {                                                                                                                         
   return new Date( this.DateJoined.getTime() );
 }                                                                                                                        
}


public class OrganizationHelper{
    public static void main(String args[]){
    Organization test=Organization.getInstance();
    Member member1 = new Member();
    Member member2 = new Member();
    Date date1 = null;
    Date date2 = null;
SimpleDateFormat fmt=new SimpleDateFormat("yyyy-MM-dd");
try {
            date1 = fmt.parse("1992-06-12");
    date2 = fmt.parse("2001-03-03");
} catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
member1.set("Tom","Cruise",date1);


member2.set("Xiao","Lizi",date2);
        test.add(member1);
        test.add(member2);
        ArrayList<Member> List = test.getMembers();
        for(int i=0;i<List.size();i++)
        {
        System.out.println(List.get(i).firstName);
        System.out.println(List.get(i).lastName);
        System.out.println(List.get(i).DateJoined);
        }
        
    }
}



[解决办法]
引用:
1)建立一个叫做Organization的类,它不能被实例化超过一次但是可以提供给全局。它包含仅一个叫做getMembers 的public method,返回一个collection.


1) 这题目的意思是实例化控制,实例化控制在Java里有两种常用手段: 

a. enum 类型天生自带实例化控制,并且对反射、反序列化之类的hack免疫, 
b. 普通类可以通过限制【构造方法】的可见性来控制实例化(可以被反射、反序列化之类的手段hack,不过这里hack应该不在考虑之列),比如把构造方法定义为 private。 (Java中如果你不写构造方法,有一个默认的 public 的无参构造方法)

实例化控制中,一种情况是全局只允许产生一个实例,即通常说的“单例”。

所以 1) 大概是下面这样:



import java.util.Collection;
import java.util.Collections;

public class Organization {
  
  private static Organization INSTANCE = new Organization();
  
  public static Organization getInstance() {
    
    return INSTANCE;
  }
  
  private Collection<Member> members;
  
  private Organization() {
    
    // TODO ...
  }
  
  public Collection<Member> getMembers() {
    
    return Collections.unmodifiableCollection(members);
  }
}


用户代码获取 Member 大概是这样的:




    for(Member member : Organization.getInstance().getMembers()) {
      
      // TODO ...
    }

[解决办法]
我不是大神。。。我说说我的看法
第一题
单利模式getInstance方法得加上public,才能提供给全局,就是用类名直接访问。
第二题
bean这里应该就是指实体类Member吧。。。
Member里加上有参构造方法和无参构造方法,set和get方法
DateJoined直接赋值就行了
第三题
OrganizationHelper属于工具类,加个静态的打印方法就行了。
具体的我试着写了下:
import java.util.ArrayList;
import java.util.Date;

public class Organization {
  private ArrayList<Member> List = new ArrayList<Member>();  
  public void addMember(Member temp)
  {
  List.add(temp);   
  }
  private static Organization instance=null;
  private Organization(){}
  public static Organization getInstance(){
      if(instance==null)
      instance=new Organization();
      return instance;
  }
  public ArrayList<Member> getMembers()
  {
  return List;
  }
}

class Member                              
{                                                               
 public String firstName;                                     
 public String lastName;                                      
 public Date dateJoined; 
 
 public Member() {
 
 }
                                         


public Member( String firstName, String lastName, Date dateJoined)           
{                                                                                                                         
    this.firstName = firstName;          
    this.lastName = lastName;            
    this.dateJoined = dateJoined; 
 }

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public Date getDateJoined() {
return dateJoined;
}

public void setDateJoined(Date dateJoined) {
this.dateJoined = dateJoined;
}                                                                                                                         
                                                            
}



public class OrganizationHelper{

public static void showInfo(Organization organization) {//打印方法
List<Member> members = organization.getMembers();
for(int i=0; i<members.size(); i++) {
System.out.println(members.get(i).firstName);
        System.out.println(members.get(i).lastName);
        System.out.println(members.get(i).dateJoined);
}
}

    public static void main(String args[]){//入口函数放哪里都可以
    Organization test=Organization.getInstance();
    Date date1 = null;
    Date date2 = null;
SimpleDateFormat fmt=new SimpleDateFormat("yyyy-MM-dd");
try {
            date1 = fmt.parse("1992-06-12");
    date2 = fmt.parse("2001-03-03");
} catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
Member member1 = new Member("Tom","Cruise",date1);
    Member member2 = new Member("Xiao","Lizi",date2);
        test.addMember(member1);
        test.addMember(member2);
        OrganizationHelper.showInfo(test);
    }
}



[解决办法]
引用:
2) 建立另一个叫做Member的类,publicly exposes(公共得包括?) FirstName, lastName 和 DateJoined bean properties,请使用合适的数据类型


2) bean,所谓 java bean, POJO, entity 等等这些名词,通常是指最简单的类: 有成员,每个成员有 getter 和 setter 方法,并且这些 getter 和 setter 方法都按规则命名: X 成员的 getter 方法就是 public X getX();

这种命名规范是为了对反射友好,当你知道这个类有一个 Field 是 String firstName, 你就知道这个类必然有方法: public void setFirstName(String) 来给 firstName 赋值。

对反射友好,所以其他的代码(通常是框架实现的代码)就能用反射的方式对这种类的对象进行序列化与反序列化,常用的存储对象的方式是 XML, 所以你“百度到javaBean但是好像是和html结合起来用的”

比如这样写的 Member 类:



import java.util.Date;


public // <-- publicly exposes
class Member {
  
  private String firstName;
  
  private String lastName;
  
  private Date joinedDate;

  public String getFirstName() {
    
    return firstName;
  }

  public void setFirstName(String firstName) {
    
    this.firstName = firstName;
  }

  public String getLastName() {
    
    return lastName;
  }

  public void setLastName(String lastName) {
    
    this.lastName = lastName;
  }

  public Date getJoinedDate() {
    
    return joinedDate == null ? null : new Date(joinedDate.getTime());
  }

  public void setJoinedDate(Date joinedDate) {
    
    this.joinedDate = joinedDate == null ? null : new Date(joinedDate.getTime());
  }
}



存储成 XML 的格式可以这样:


/*
 * <Member>
 *   <FirstName>Raistlin</FirstName>
 *   <LastName>Majere</LastName>
 *   <JoinedDate>2013-09-05</JoinedDate>
 * </Member>
 */

[解决办法]
引用:
3)建立第三个叫做OrganizationHelper的类,包含一个method用于输出Organization类中所有Members的数据。输出的类型随意。


3) 在 2) 中的实体类只做存储信息之用,所以只有 getter 和 setter 方法,这里的 helper 类就是所谓“业务逻辑”了,业务逻辑和实体类分开,是为了更清晰的层面,以及实体类的复用。

比如有下面的 memberlist.xml:


<?xml version="1.0" encoding="UTF-8"?>
<root>
  
    <Member>
      <FirstName>123</FirstName>
      <LastName>A</LastName>
      <JoinedDate>2013-09-05</JoinedDate>
    </Member>
    
    <Member>
      <FirstName>124</FirstName>


      <LastName>B</LastName>
      <JoinedDate>2013-09-05</JoinedDate>
    </Member>
    
    <Member>
      <FirstName>125</FirstName>
      <LastName>C</LastName>
      <JoinedDate>2013-09-05</JoinedDate>
    </Member>
    
    <Member>
      <FirstName>126</FirstName>
      <LastName>D</LastName>
      <JoinedDate>2013-09-05</JoinedDate>
    </Member>
    
    <Member>
      <FirstName>127</FirstName>
      <LastName>E</LastName>
      <JoinedDate>2013-09-05</JoinedDate>
    </Member>
</root>



简单完成 Organization 类如下:



import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Organization {
  
  private static final Organization INSTANCE = new Organization();
  
  public static Organization getInstance() {
    
    return INSTANCE;
  }
  
  private Collection<Member> members;
  
  private Organization() {
    
    members = loadMembers();
  }
  
  private Collection<Member> loadMembers() {
    
    try {
      
      List<Member> result = new ArrayList<Member>();
      Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(


              getClass().getResourceAsStream("memberlist.xml"));
      
      DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
      
      NodeList list = doc.getDocumentElement().getChildNodes();
      Map<String, Field> fields = fieldsOf(Member.class);
      
      for(int k=0; k<list.getLength(); k++) {
        
        Node node = list.item(k);
        if( !node.getNodeName().equals("Member") )
          continue;
        
        Member member = Member.class.newInstance();
        
        NodeList l = node.getChildNodes();
        for(int j=0, len=l.getLength(); j<len; j++) {
          
          Node m = l.item(j);
          String name = m.getNodeName();
          Field field = fields.get(name);
          if( field == null )
            continue;
          
          String methodName = "set" + name;
          if( field.getType().equals(Date.class) ) {
            
            Method method = Member.class.getMethod(
                    methodName, new Class<?>[]{Date.class});
            Date value = format.parse(m.getTextContent());
            method.setAccessible(true);
            method.invoke(member, value);


          }
          else {
            
            Method method = Member.class.getMethod(
                    methodName, new Class<?>[]{String.class});
            method.setAccessible(true);
            method.invoke(member, m.getTextContent());
          }
        }
        
        result.add(member);
      }
      return result;
    }
    catch (Exception e) {
      
      e.printStackTrace();
      throw new RuntimeException(e);
    }
  }
  
  private Map<String, Field> fieldsOf(Class<?> type) {
    
    Map<String, Field> result = new HashMap<String, Field>();
    Field[] fields = type.getDeclaredFields();
    for(Field f : fields)
      result.put(Character.toUpperCase(f.getName().charAt(0)) + f.getName().substring(1), f);
    return result;
  }
  
  public Collection<Member> getMembers() {
    
    return Collections.unmodifiableCollection(members);
  }
}



那么 OrganizationHelper 类大概是这样的:



import java.text.DateFormat;
import java.text.SimpleDateFormat;

public class OrganizationHelper {
  
  public void print(Member member) {
    
    if( member == null )
      throw new NullPointerException();
    
    DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    System.out.printf("%-15s%s%n", "First Name:", member.getFirstName());


    System.out.printf("%-15s%s%n", "Last Name:", member.getLastName());
    System.out.printf("%-15s%s%n", "Joined Date:", format.format(member.getJoinedDate()));
    System.out.println();
  }
  
  public static void main(String[] args) {
    
    OrganizationHelper helper = new OrganizationHelper();
    
    for(Member m : Organization.getInstance().getMembers())
      helper.print(m);
  }
}




[解决办法]
引用:
我其实被java中的反射绕晕...我是不是可以理解为反射友好就是java为了能够方便动态赋值而规定了要有哪些method,method该叫作什么名字,有一套明确的规范?


是的,详见7楼示例代码。

实际应用中一般不用自己调用 XML parsing 的库(DOM,JAX……),因为 Java 内建了 JAXB,通过给类加适当的 annotation,就可以用 JAXB 自动加载对象或把对象写成xml。 另外像 Spring 这样的框架也可以帮你完成。
[解决办法]
引用:
1. 我想问一下“Java中如果你不写构造方法,有一个默认的 public 的无参构造方法”是不是如果不谢public或者private,都是统一默认成public?
2. 所以本题的确是通常所说的单例吗?
这里是不是用getInstance来获取对象?
3. private Organization() {
     
    // TODO ...
  } 
  里面是不是作add member操作还是说,add member不在Organization里面完成,那么又是在哪里完成的呢?
4. Collection 在这里是不是和 Array 相似的数组,Collections.unmodifiableCollection(members) 是整个数组吗?
5. for(Member member : Organization.getInstance().getMembers()) {
       
      // TODO ...
    } 中是否应该进行题目中的输出?

太谢谢了!


1 - 是的,所以这里你需要写  private Organization() { ... }

2 - 是的, getInstance 是静态方法,每次调用都是返回那个唯一的实例

3 - 见 7 楼

4 - Collection 是更抽象的接口“集合”,比如可以是 tree set, 可以是 hash map,也可以是 list 或者 array,它定义的只是所有“集合”都应该具备的行为
Collections.unmodifiableCollection 的作用相当于 defensive copy,加一层“壳”变成只读,只是不想让外部代码随意更改 Organization 的内部状态

5 - 是,见 7 楼

[解决办法]
引用:


DateJoined bean properties是什么不懂,其它我就按字面意思做,如下:



 

热点排行