Философия Java3
Шрифт:
Pet.class, Dog class. Cat.class, Rodent.class, Mutt class. Pug.class. EgyptianMau.class. Manx.class. Cymric class. Rat.class. Mous'e.class.Hamster.class)); // Типы для случайного создания: private static final List<Class<? extends Pet» types = al1 Types.subLi st(al1 Types.i ndexOf(Mutt.class). allTypes.sizeO); public List<Class<? extends Pet» types { return types;
}
public static void main(String[] args) { System.out.printin(types);
}
} /* Output:
[class typeinfo pets.Mutt, class typeinfo.pets.Pug. class typeinfo.pets.EgyptianMau. class typeinfo pets Manx, class typeinfo.pets.Cymric, class typeinfo.pets.Rat, class typeinfo.pets.Mouse, class typeinfo.pets.Hamster] *///.-
В будущем примере PetCount3.java контейнер Map заполняется всеми типами Pet (не только генерируемыми случайным образом), поэтому нам понадобился список allTypes. Список types представляет собой часть allTypes (создается вызовом List.subList) со всеми типами Pet, поэтому он используется для случайного генерирования Pet.
На этот раз при создании types блок try не нужен, так как необходимые проверки типов проводятся еще во время компиляции и исключения не возбуждаются, в отличие от метода Class.forName.
Теперь библиотека typeinfo.pets содержит две реализации PetCreator. Чтобы вторая реализация использовалась по умолчанию, мы можем создать фасад (fagade), использующий LiteralPetCreator:
//• typeinfo/pets/Pets java
// Фасад для получения PetCreator по умолчанию
package typeinfo.pets, import java util *,
public class Pets {
public static final PetCreator creator =
new LiteralPetCreator; public static Pet randomPetO {
return creator.randomPetO:
}
public static Pet[] createArray(int size) { return creator.createArray(size).
}
public static ArrayList<Pet> arrayListOnt size) { return creator arrayList(size);
}
} ///:-
При этом также обеспечиваются косвенные вызовы randomPet, createArray и arrayList.
Поскольку PetCount.countPets получает аргумент PetCreator, мы можем легко проверить работу LiteralPetCreator (через представленный фасад):
II. typeinfo/PetCount2.java import typeinfo pets *.
public class PetCount2 {
public static void main(String[] args) { PetCount.countPets(Pets creator),
}
} /* (Выполните, чтобы увидеть результат) *///:-Результат будет таким же, как у PetCount.java.
Динамический вызов instanceof
Метод Class.islnstance позволяет выполнить динамическую проверку типа объекта. Благодаря ему в примере PetCount.java наконец-то можно будет избавиться от нагромождения instanceof:
II: typeinfо/PetCount3.java
// Using isInstanceO
import typeinfo.pets.*:
import java.util.*,
import net.mindview.util *;
import static net.mindview util Print *;
public class PetCount3 {
static class PetCounter
extends LinkedHashMap<Class<? extends Pet>,Integer> { public PetCounter {
super(MapData map(LiteralPetCreator.allTypes, 0)).
}
public void count(Pet pet) {
// Class.isInstanceO избавляет от множественных instanceof: for(Map Entry<Class<? extends Pet>.Integer> pair entrySetO) if(pair.getKey.islnstance(pet))
put(pair.getKey. pair.getValueO + 1):
продолжение &
}
public String toStringO {
StringBuilder result = new StringBuilder("{"); for(Map.Entry<Class<? extends Pet>,Integer> pair : entrySetO) {
result.append(pai r.getKey.getSi mpleName);
result.append("=");
result.append(pai r.getValue);
result.appendC, ");
}
result.delete(result.1ength0 -2, result.1ength); result.append("J"); return result.toStringO;
}
}
public static void main(String[] args) {
PetCounter petCount = new PetCounterO;
for(Pet pet : Pets.createArray(20)) {
printnbCpet.getClassO.getSimpleNameO + " "); petCount.count(pet);
}
printO;
print(petCount);
}
} /* Output:
Rat Manx Cymric Mutt Pug Cymric Pug Manx Cymric Rat EgyptianMau Hamster EgyptianMau Mutt Mutt Cymric Mouse Pug Mouse Cymric
{Pet=20, Dog=6. Cat-9. Rodent=5, Mutt-3. Pug=3. EgyptianMau=2, Manx=7, Cymric=5, Rat=2,
Mouse=2, Hamster=l}
*///:-
Для подсчета всех разновидностей Pet контейнер PetCounter Map заполняется типами из LiteralPetCreator.allTypes. При этом используется класс net.mindview. util.MapData, который получает Iterable (allTypesList) и константу (0 в данном случае) и заполняет Map ключами из allTypes со значениями 0. Без предварительного заполнения Map будут подсчитаны только случайно сгенерированные типы, но не базовые типы (такие, как Pet и Cat).
Как видите, метод islnstance избавил нас от необходимости нагромождать конструкции с instanceof. Вдобавок теперь в программу можно легко добавить новые типы Pet — для этого следует просто изменить массив LiteralPet Creator, types; остальная часть программы не потребует правки (которая была бы неизбежна с операторами instanceof).
Метод toStringO был перегружен для получения удобочитаемого вывода.
Рекурсивный подсчет
Контейнер Map в PetCount3.PetCounter был заполнен всеми классами Pet. Вместо предварительного заполнения карты мы также можем воспользоваться методом Class.isAssignableFrom и создать обобщенный инструмент подсчета, не ограниченный подсчетом Pet:
//: net/mi ndvi ew/uti1/TypeCounter.java // Подсчет экземпляров в семействе типов package net.mindview.util;
import java.util.*;
public class TypeCounter extends HashMap<Class<?>,Integer>{ private Class<?> baseType; public TypeCounter(CIass<?> baseType) { this.baseType = baseType;