读书人

一路关于单例模式的题

发布时间: 2013-09-07 14:12:44 作者: rapoo

一道关于单例模式的题
本帖最后由 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 的库—OM,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是什么不懂,其它我就按字面意思做,如下:



 

读书人网 >J2SE开发

热点推荐