class Class1
{
friend: Class2;
private:
int a, b;
};
class Class2
{
public:
changer(Classs1 *data int _a, int _b);
};
void Class2::changer(Classs1 *data int _a, int _b)
{
data->a = _a;
data->b = _b;
}
* This source code was highlighted with Source Code Highlighter.
Дружественые классы в Java - возможно ли это? И нужно ли вообще? На первый взгляд - казалось бы, не нужно. Ведь в Java отсутствует перегрузка операторов (а как правило, дружественные функции в программах на C++ - это функции-операторы). Но порой нужно, чтобы между классами были "особые отношения": например, Class1 содержит некие поля
данных, но "не знает", как эти поля корректно загружать из файла какого-то формата или получать от пользователя. Зато ClassA знает, как загружать/сохранять данные в формате A, ClassB знает как загружать/сохранять данные в формате B, а ClassUser умеет эти данные получать от пользователя/передавать пользователю. На первый взгляд, можно сделать Class1 абстрактным классом, содержащим абстрактные методы для загрузки/сохранения полей данных, и в классах ClassA и ClassB реализовать эти методы. Теперь мы сможем загружать и сохранять данные обоих форматов. А если необходимо загрузить данные из формата A и сохранить их в формате B? И при этом некоторые из полей данных класса Class1 только для чтения?
Сформулируем задачу следующим образом. Классы данных и форматов не связаны родственными узами, поскольку они все же решают разные задачи: Class1 позволяет хранить данные и как-то ими манипулировать, а классы ClassA и ClassB позволяют сохранять/загружать данные различных форматов. Но при этом классы ClassA и ClassB должны иметь доступ на запись к тем полям Class1, которые остальные классы могут только читать. И такие отношения в парах классов Class1 - ClassA и Class1 - ClassB можно назвать если не дружественными, то , по крайней мере, приятельскими :)
Мое решение проблемы:
Помещаем классы Class1, ClassA, ClassB в один пакет. Содержимое файла Class1.java:
package friends;
public abstract class Class1
{
public abstract int getOne();
public abstract int getTwo();
public abstract void setTwo(int _two);
public static Class1 getInstance()
{ return new InnerFriend(); }
}
class InnerFriend extends Class1
{
private int one = 0, //Поле только для чтения
two = 0; //Поле для чтения и записи
public int getOne()
{ return one; }
public int getTwo()
{ return two; }
public void setTwo(int _two)
{ two = _two; }
//Методы, доступные только дружественным классам:
public void setOne(int _one)
{ one = _one; }
}
* This source code was highlighted with Source Code Highlighter.
Как видите, тут появился еще один персонаж - класс InnerFriend (внутренний друг, противоположность внутреннему врагу :)))) ). Внешние по отношению к пакету friends классы "не видят" его, поэтому не могут обратится к тем его методам, которые отсутствуют в публичном классе Class1. Классы, находящиеся в пакете friends, могут преобразовать ссылку на Class1 в ссылку на InnerFriend и, таким образом, получить доступ к методам, которых нет в Class1, но которые есть в InnerFriend. В качестве примера я создал 2 класса форматов - ClassA загружает/сохраняет данные текстового формата, ClassB загружает/сохраняет двоичные данные.
package friends;
import java.io.*;
public class ClassA implements IFormat
{
public void loadData(Class1 _dta, String fname) throws IOException, FileNotFoundException
{
if(!(_dta instanceof InnerFriend) )
throw new IllegalArgumentException();
InnerFriend dta = (InnerFriend)_dta;
BufferedReader in = new BufferedReader(new FileReader(fname));
dta.setOne(Integer.parseInt(in.readLine()));
dta.setTwo(Integer.parseInt(in.readLine()));
in.close();
}
public void saveData(Class1 dta, String fname) throws IOException,
FileNotFoundException
{
PrintStream out = new PrintStream(fname);
out.println(dta.getOne());
out.println(dta.getTwo());
out.close();
}
}
* This source code was highlighted with Source Code Highlighter.
package friends;
import java.io.*;
public class ClassB implements IFormat
{
public void loadData(Class1 _dta, String fname) throws IOException,
FileNotFoundException
{
if(!(_dta instanceof InnerFriend) )
throw new IllegalArgumentException();
InnerFriend dta = (InnerFriend)_dta;
DataInputStream in = new DataInputStream(
new FileInputStream(fname));
dta.setOne(in.readInt());
dta.setTwo(in.readInt());
in.close();
}
public void saveData(Class1 dta, String fname) throws IOException,
FileNotFoundException
{
DataOutputStream out = new DataOutputStream(
new FileOutputStream(fname));
out.writeInt(dta.getOne());
out.writeInt(dta.getTwo());
out.close();
}
}
* This source code was highlighted with Source Code Highlighter.
Оба класса реализуют интерфейс IFormat:
package friends;
import java.io.*;
public interface IFormat
{
void loadData(Class1 _dta, String fname) throws IOException,
FileNotFoundException;
void saveData(Class1 dta, String fname) throws IOException,
FileNotFoundException;
}
* This source code was highlighted with Source Code Highlighter.
Теперь можно написать небольшой тест, который будет читать данные из файла текстового формата, изменять поля, доступное для записи и сохранять измененные данные в файле двоичного формата:
import friends.*;
public class TestFriends
{
public static void main(String args[]) throws java.io.IOException
{
Class1 data = Class1.getInstance();
System.out.println("Read text file:");
//Загрузка данных из текстового файла:
IFormat format = new ClassA();
format.loadData(data, args[0]);
System.out.println("Value of one = " + data.getOne());
System.out.println("Value of two = " + data.getTwo());
//Изменяем одно из полей
data.setTwo(0x771177);
//Попытка изменить поле только для чтения
// fr1.setOne(0x771177);
// ((InnerFriend)fr1).setOne(0x771177);
//Сохранение в двоичном формате:
format = new ClassB();
format.saveData(data, args[1]);
}
}
* This source code was highlighted with Source Code Highlighter.
0 коммент.:
Отправить комментарий