Gangmax Blog

Restriction of Computer Language: Good or Bad

这两天在使用Eclipse进行PDE开发的时候遇到这样一个问题。

我自定义的一个WizardPage类继承自Eclipse的”org.eclipse.ui.dialogs.WizardNewProjectCreationPage”类。我的WizardPage类中包含一些Text需要用户输入。现在有这样一个需求:当用户在当前WizardPage输入”projct name”的时候,我的WizardPage定义的那些Text需要根据用户的输入随时变化。

输入”project name”的Text是由”WizardNewProjectCreationPage”定义的,也就是被定义在我的WizardPage类的父类中。这个功能最直接的实现是:在我的类中,得到父类中该Text变量的引用,然后调用它的addListener()方法,加入一个Listener的实现,该Listener做的事情就是根据当前”project name”Text的内容设置其它我自定义的Text的内容。

但是看了”WizardNewProjectCreationPage”的代码后,我发现这件事情是没办法直接做的:

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*******************************************************************************
* Copyright (c) 2000, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jakub Jurkiewicz <jakub.jurkiewicz@gmail.com> - Fix for Bug 174737
* [IDE] New Plug-in Project wizard status handling is inconsistent
* Oakland Software Incorporated (Francis Upton) <francisu@ieee.org>
* Bug 224997 [Workbench] Impossible to copy project
*******************************************************************************/
package org.eclipse.ui.dialogs;

import java.net.URI;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
import org.eclipse.ui.internal.ide.dialogs.ProjectContentsLocationArea;
import org.eclipse.ui.internal.ide.dialogs.ProjectContentsLocationArea.IErrorMessageReporter;

/**
* Standard main page for a wizard that is creates a project resource.
* <p>
* This page may be used by clients as-is; it may be also be subclassed to suit.
* </p>
* <p>
* Example usage:
* <pre>
* mainPage = new WizardNewProjectCreationPage("basicNewProjectPage");
* mainPage.setTitle("Project");
* mainPage.setDescription("Create a new project resource.");
* </pre>
* </p>
*/
public class WizardNewProjectCreationPage extends WizardPage {

// initial value stores
private String initialProjectFieldValue;

// widgets
Text projectNameField;

...
}

请注意第65行,这行指定”projectNameField”的作用域是默认的”friendly”,也就是说,我定义的子类是不能通过变量名访问该变量的。再看该类的其它内容,也没有暴露出该变量对应的get方法。也就是说,由于该类作者的限制,作为该类的子类,我的代码是无法通过常规方法访问该变量的。

幸运的是,在这个例子中我还可以通过反射的方式取得父类中该变量的引用,然后完成功能。但是在有些情况下,如果代码的原作者不够配合(希望大家都不要成为这样的作者),想复用代码可能就很难了:想象一下你想修改或继承的类被声明成了final。

当然,你可能会说既然代码的作者已经声明为final,那就是不想让别人继承。但是不要忘记,任何人都会犯错,都会有考虑不到的地方。而且我很怀疑作为一个类的作者(尤其是Eclipse PDE的基本实现类),是否存在一种情况,在这种情况下你应该拒绝别人扩展你的代码。类似的观点Neal Ford在一次InfoQ的访问中曾经提到过:他不理解为什么Java语言中的一些基础类,比如String,是声明为final而不允许别人扩展的。对于这个问题,你的第一反应可能是答案很简单:就是因为Java的实现者觉得一些基础类不应该被修改。但是深入想一下,这个问题其实没有这么简单。

在Ruby这样的语言中,你就可以修改类似String这样基础类的行为。这不但没有成为一个问题,反而成为了Ruby语言强大力量的一个来源:作为这种语言的使用者,你甚至可以为了你的功能修改这种语言自身,这是多么强大的功能!

Paul Graham曾在他的”Five Questions about Language Design“一文中列举了设计”计算机语言”时应该考虑的五个问题:

1
2
3
4
5
1. Programming Languages Are for People.
2. Design for Yourself and Your Friends.
3. Give the Programmer as Much Control as Possible.
4. Aim for Brevity.
5. Admit What Hacking Is.

简而言之,一种让使用者喜欢的编程语言应该赋予使用它的人更多的自由而不是相反。

Comments