在Java中,如何实现一个类对另外两个类的单独访问?
可能的重复项:在Java中,如何实现一个类对另外两个类的单独访问?,java,Java,可能的重复项: C++中有一个“朋友”的概念,它可以访问一个类的私有变量和函数。因此,如果你有: class Foo { friend class Bar; private: int x; } 然后,类Bar的任何实例都可以修改任何Foo实例的x成员,尽管它是私有的,因为Bar是Foo的朋友 现在,我在Java中遇到了这样一种情况:这个功能会派上用场,但当然,它在Java中并不存在 有三个类:数据库、修改器、查看器。数据库只是变量的集合(如结构)。修改器应该是数据库的“朋
C++中有一个“朋友”的概念,它可以访问一个类的私有变量和函数。因此,如果你有:
class Foo {
friend class Bar;
private:
int x;
}
然后,类Bar的任何实例都可以修改任何Foo实例的x
成员,尽管它是私有的,因为Bar是Foo的朋友
现在,我在Java中遇到了这样一种情况:这个功能会派上用场,但当然,它在Java中并不存在
有三个类:数据库、修改器、查看器。数据库只是变量的集合(如结构)。修改器应该是数据库的“朋友”;也就是说,它应该能够直接读写它的变量。但查看器应该只能读取数据库的变量
如何最好地实现这一点?有没有一种好方法可以强制查看器对数据库进行只读访问?我认为这不是实现这种功能的好方法 您应该有一个隐藏数据库的数据访问层。它应该公开CRUD操作 从接口开始。创建一个只有finder方法的ReaderDao。然后创建一个GenericDao,扩展ReaderDao并添加save、insert和delete方法 实现类应根据需要实现一个或另一个接口
任何人都不需要公开这是一个幕后关系数据库的事实。关于你应该有多纯洁,人们有不同的看法,但对我来说,你不应该让任何人访问任何领域。使用getter和setter 如果你需要区分谁能读谁能写,你可以把接口加入其中。定义一个只包含getter的接口,您可以将查看器限制为只读
Robert Harvey添加了一条评论,指出了其他选项,例如对类或包级别的访问使用不同的访问修饰符。内部类可以访问其容器类的所有私有成员。将getter设置为公共的,setter设置为私有的,将modifier设置为数据库的内部类。也使它只能通过工厂方法模式从数据库内部创建。可能也需要单身
一个包本地类与C++中的“朋友”差不多。将所有getter公开,将setter包本地化。使修改器与数据库位于同一个包中。第一个例子是更干净
另一个适用的习语是Memento模式 你确定这是个好模式吗?它直接绕过了封装,封装是OO设计的主要特点之一。您可以创建一个嵌套类 假设您有这样的ViewClass:
class Viewer {
Database db;
Viewer( Database db ){
this.db = db;
}
public void whatIsX(){
System.out.println( db.x() );
}
}
class Viewer {
Database db;
public Viewer( Database db ){
this.db = db;
}
public void whatIsX(){
System.out.println( db.x() );
}
}
class Modifier {
Database db;
public Modifier( Database db ){
this.db = db;
}
public void manipulate(){
//db.x++; doesn't work because db.x is private
}
}
class Database {
private int x;
static class DatabaseModifier extends Modifier {
public DatabaseModifier( Database db ){
super(db);
}
@Override
public void manipulate(){
db.x++;
}
}
// public accessor to attribute X
public int x(){// should be getX()
return x;
}
}
class Main{
public static void main( String [] args ) {
Database database = new Database();
Modifier modifier = new Database.DatabaseModifier( database );
Viewer viewer = new Viewer( database );
viewer.whatIsX();
modifier.manipulate();
viewer.whatIsX();
}
}
public class Database {
public DatabaseReadAccess getReadAccess(Viewer viewer) { ... }
public DatabaseWriteAccess getWriteAccess(Modifier modifier) { ... }
}
并使用修改该数据库的方法定义一个修饰符
abstract class Modifier {
public void manipulate();
}
您可以使用嵌套类创建数据库,该类可以访问私有成员,与friend非常相似
class Database {
private int x;
class DatabaseModifier extends Modifier {
public void manipulate(){
x++;
}
}
public int x(){
return x;
}
}
//要查看是否有效,请执行以下操作:
class Main{
public static void main( String [] args ) {
Database database = new Database();
Modifier modifier = database.new DatabaseModifier();
Viewer viewer = new Viewer( database );
viewer.whatIsX();
modifier.manipulate();
viewer.whatIsX();
}
}
您还可以选择静态内部类。可能是这样的:
class Viewer {
Database db;
Viewer( Database db ){
this.db = db;
}
public void whatIsX(){
System.out.println( db.x() );
}
}
class Viewer {
Database db;
public Viewer( Database db ){
this.db = db;
}
public void whatIsX(){
System.out.println( db.x() );
}
}
class Modifier {
Database db;
public Modifier( Database db ){
this.db = db;
}
public void manipulate(){
//db.x++; doesn't work because db.x is private
}
}
class Database {
private int x;
static class DatabaseModifier extends Modifier {
public DatabaseModifier( Database db ){
super(db);
}
@Override
public void manipulate(){
db.x++;
}
}
// public accessor to attribute X
public int x(){// should be getX()
return x;
}
}
class Main{
public static void main( String [] args ) {
Database database = new Database();
Modifier modifier = new Database.DatabaseModifier( database );
Viewer viewer = new Viewer( database );
viewer.whatIsX();
modifier.manipulate();
viewer.whatIsX();
}
}
public class Database {
public DatabaseReadAccess getReadAccess(Viewer viewer) { ... }
public DatabaseWriteAccess getWriteAccess(Modifier modifier) { ... }
}
如果需要这种访问,请创建一个类接口,该接口封装了只允许少数几个方法调用的方法。然后创建一个方法,仅当请求类满足您强加的任何条件时,该类才会传递接口的私有实例 一个简单的例子,写得很刻薄:
public class Husband {
private Spouse wife;
private int cashInWallet;
public Husband(Wife wife) {
this.cashInWallet = 20;
this.wife = wife;
}
public WalletAccess getWalletAccess(Object other) {
if (other instanceof Wife) {
return new WalletAccessImpl(this);
}
return null;
}
public interface WalletAccess {
public int withdrawCash(int requested);
}
private WalletAccessImpl implements WalletAccess {
private Husband hubby;
private WalletAccessImpl(Husband hubby) {
this.hubby = hubby;
}
public int withdrawCach(int requested) {
if (this.hubby.wallet > requested) {
this.hubby.wallet -= requested;
return requested;
} else {
int allCash = this.hubby.wallet;
this.hubby.wallet = 0;
return allCash;
}
}
}
public class Wife {
private Husband husband;
public Wife(Husband husband) {
this.husband = husband;
}
public void consumeCash() {
Husband.WalletAccess access = husband.getWalletAccess(this);
int cash = access.withdrawCash(20);
}
}
更复杂的示例是可能的,但这改进了friend访问模式,因为即使是“潜在”friend类的单个实例也可以被单独挑选出来进行访问(或拒绝)。例如,在本例中,通过重写getWalletAccess(…)来检查妻子是否真的与这个特定的丈夫结婚是很简单的,如下所示:
我想说,接口绝对是解决您问题的方法 首先,不允许任何其他内容访问
数据库的实际字段。创建每个返回其一个字段的方法。然后,使DatabaseView
成为一个接口,该接口声明了这些方法中的每一种,以供读取。然后让数据库
实现数据库视图
。最后,您可以添加写入(设置)应设置为数据库的字段的方法
当您有一些类需要能够从数据库中读取时,例如您的查看器
,让它使用数据库视图
。然后可以传入数据库
实例本身,但该类不知道写入该实例的方法。如果还需要读写其他内容,例如修饰符
,则只需将数据库
本身交给它即可。更好的是,数据库
本身可以是一个扩展数据库视图
的接口,而您的实际实现对象可以是一些不需要知道的类。您应该重新考虑您真正想要的分离程度,这个“修饰符应该是”朋友“有数据库;也就是说,它应该能够直接读写它的变量。”这在Java中是不可能的——直接字段访问不能有不同的访问权限
我认为您真正想要的是强烈反对不受欢迎的访问模式。有几种方法可以实现这一点:
1.)将修改器和数据库放在同一个包中,并使“Setters”包受到保护,因此设置的方法对查看器不可见(只要查看器不在同一个包中)。这对于较大的设计或多或少是不切实际的
2.)将关注点分离为完全不同的项目。然后您可以设置项目依赖项,只有修改器才能访问数据库。这意味着您在某种程度上改变了设计,任一数据库都会变成两个项目(一个具有公共只读接口,另一个具有完全访问接口),或完全删除查看器和数据库之间的依赖关系,并使查看器仅访问数据库