Viditelné "uživatelské" rozhraní k abstrakcím
Select() v C#
public static void Select(
IList checkRead, IList checkWrite, IList checkError,
int microseconds
);
int select(
int nfds,
fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
struct timeval * timeout
);
Select() v C#
int timeout = ...;
ArrayList readList = ...; // sockets to monitor for reading
ArrayList writeList = ...; // sockets to monitor for writing
ArrayList errorList = ...; // sockets to monitor for errors
while (!done) {
ArrayList checkRead = readList.Clone();
ArrayList checkWrite = writeList.Clone();
ArrayList checkError = errorList.Clone();
Select(checkRead, checkWrite, checkError, timeout);
foreach (Socket socket in checkRead) {
// deal with each socket ready for reading
}
foreach (Socket socket in checkWrite) {
// deal with each socket ready for writing
}
foreach (Socket socket in checkError) {
// deal with each socket that encountered an error
}
if (checkRead.Count == 0 && checkWrite.Count == 0 && checkError.Count == 0) {
// no sockets are ready -- timed out...
}
)
Select() v C#
private static boolean hasActiveSocket(
IList readList, IList writeList, IList errorList
) {
bool readListEmpty = (readList == null || readList.Count == 0);
bool writeListEmpty = (writeList == null || writeList.Count == 0);
bool errorListEmpty = (errorList == null || errorList.Count == 0);
return !readListEmpty || !writeListEmpty || !errorListEmpty;
}
IList ani top-level objekt nemá Clone()Clone(), musí implementovat ICloneableSelect() v C#doSelect()
public static void doSelect(
IList checkRead, IList checkWrite, IList checkError, int milliseconds
) {
ArrayList readCopy; // copies of the three parameters
ArrayList writeCopy; // because Select() clobbers them
ArrayList errorCopy;
if (milliseconds <= 0) {
// simulate waiting forever
do {
... // copy socket lists
Select(readCopy, writeCopy, errorCopy, Int32.MaxValue);
} while (!hasActiveSocket(readCopy, writeCopy, errorCopy));
} else {
// handle finite timeouts
int maxMilliseconds = Int32.MaxValue / 1000;
int remaining = milliseconds;
while ((remaining > 0) && !hasActiveSocket(readCopy, writeCopy, errorCopy)) {
int timeout = milliseconds > maxMilliseconds ? maxMilliseconds : milliseconds;
... // copy socket lists
Select(readCopy, writeCopy, errorCopy, timeout * 1000);
remaining -= timeout;
}
... // copy the three lists back to original parameters
}
Select() v C#Select()
public static int Select (
ISet checkRead, ISet checkWrite, Timespan timeout,
out ISet readable, out ISet writable, out ISet error
);
public final class ThreadLocal {
private ThreadLocal() { /* non-instantiable */ }
// Sets current thread's value for named variable.
public static void set(String key, Object value);
// Returns current thread's value for named variable.
public static <T> T get(String key, Class<T> type);
}
public final class ThreadLocal {
private ThreadLocal() { /* non-instantiable */ }
public static final class Key { private Key() { } };
// Generates unique, unforgeable key
public static Key getKey() { return new Key(); }
public static void set(Key key, Object value);
public static <T> T get(Key key, Class<T> type);
}
static ThreadLocal.Key serialNumberKey = ThreadLocal.getKey();
ThreadLocal.set(serialNumberKey, nextSerialNumber());
System.out.println(ThreadLocal.get(serialNumberKey, int.class));
public final class ThreadLocal<T> {
public ThreadLocal() { }
public void set(T value);
public T get();
}
static ThreadLocal<Long> serialNumber = new ThreadLocal<>();
serialNumber.set(nextSerialNumber());
System.out.println(serialNumber.get());
Myslete na uživatele.
Minimalizujte údiv uživatele.
"A user interface is well-designed when the program behaves exactly how the user thought it would." — Joel Spolsky
Dělejte jen jednu věc a dělejte ji dobře.
Usilujte o co nejjednodušší možné řešení.
"Keep It Simple, Stupid." – anonym
"When in doubt, leave it out." – Joshua Bloch
"Everything should be made as simple as possible, but no simpler." – Albert Einstein
public interface Connection {
...
public Savepoint setSavepoint();
public void rollback(Savepoint sp);
...
}
public interface Savepoint {
public String getSavepointId();
public String getSavepointName();
}
public interface Connection {
...
public Savepoint setSavepoint();
...
public interface Savepoint {
public void rollback();
public String getSavepointId();
public String getSavepointName();
}
}
if (car.speed () > 2 * SPEED_LIMIT) {
generateAlert ("Watch out for cops!");
}
HttpRequest req = new HttpRequest();
req.setUrl("https://api.example.com");
req.setMethod("POST");
sendAsync(req);
req.setUrl("https://another.example.com");
HttpRequest req = new HttpRequest(
"https://api.com", "POST", 5000, true, null, "Bearer token"
);
HttpRequest req = HttpRequest.newBuilder("https://api.com")
.method("POST")
.timeout(5000)
.followRedirects(true)
.header("Authorization", "Bearer token")
.build();
build() umožňuje explicitní kontrolu konzistence parametrůString byl interface?)| Modifikátory | Primární význam | Vedlejší významy |
|---|---|---|
public |
Metoda určena k volání externími klienty API. | Může být předefinována v odvozených třídách. Může být volána z odvozených tříd. |
public abstract |
Metoda musí být implementována v odvozených třídách. | Může být volána externími klienty. |
public final |
Metoda určená pouze k volání. | Žádné. |
protected |
Metoda může být volána z odvozených tříd. | Může být předefinována v odvozených třídách. |
protected abstract |
Metoda musí být implementována v odvozených třídách. | Žádné. |
protected final |
Metoda může být volána z odvozených tříd. | Žádné. |
| Původní kód | Transformace |
|---|---|
|
|
|
|
|
|
public abstract class AbstractSensor {
private final int i2cAddress;
protected AbstractSensor (int address) {
this.i2cAddress = address;
}
// 1. API pro klienty
public final double readTemperature () {
return readFromHardware ();
}
// 2. SPI poskytované podtřídou (implementace čtení)
protected abstract double readFromHardware ();
// 3. Služba pro podtřídu (konfigurace)
protected final int getI2cAddress () {
return i2cAddress;
}
}
// Služba pro SPI (konfigurace)
public final class SensorContext {
private final int i2cAddress;
SensorContext (int address) {
this.i2cAddress = address;
}
public int getI2cAddress () {
return i2cAddress;
}
}
// SPI - rozhraní pro tvůrce pluginu.
public interface SensorProvider {
// Při inicializaci získá kontext s parametry.
void initialize (SensorContext context);
double readFromHardware ();
}
public final class Sensor {
private final SensorProvider provider;
private Sensor (SensorProvider provider) {
this.provider = provider;
}
// Factory metoda pro vytvoření senzoru.
public static Sensor create (int address, SensorProvider provider) {
SensorContext context = new SensorContext (address);
provider.initialize (context);
return new Sensor (provider);
}
// API určené pouze pro klienty.
public double readTemperature () {
return provider.readFromHardware ();
}
}
class DummyI2cSensor implements SensorProvider {
private int address;
@Override
public void initialize(SensorContext context) {
this.address = context.getI2cAddress();
}
@Override
public double readFromHardware() {
if (this.address == 0x42) {
// Čtení ze známé adresy.
return 22.5;
}
// Chyba při čtení z "nefuknční" adresy.
return -99.0;
}
}
public class SensorTest {
@Test
public void sensorWorksInIsolation() {
DummyI2cSensor provider = new DummyI2cSensor();
SensorContext context = new SensorContext(0x42);
provider.initialize(context);
assertEquals(22.5, provider.readFromHardware());
}
@Test
public void sensorWorksThroughClientApi() {
Sensor sensor = Sensor.create(0x42, new DummyI2cSensor());
assertEquals(22.5, sensors.readTemperature());
}
}
import org.w3c.dom.*;
import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
// DOM code to write an XML document to a specified output stream.
private static final void writeDoc(Document doc, OutputStream out) throws IOException {
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(
OutputKeys.DOCTYPE_SYSTEM,
doc.getDoctype().getSystemId()
);
t.transform(new DOMSource(doc), new StreamResult(out));
} catch (TransformerException e) {
throw new AssertionError(e); // Can’t happen!
}
}
public class Thread implements Runnable {
// Tests whether current thread has been interrupted.
// Clears the interrupted status of current thread
public static boolean interrupted();
}
public class Properties extends Hashtable {
public Object put(Object key, Object value);
// Throws ClassCastException if this properties
// contains any keys or values that are not Strings
public void save(OutputStream out, String comments);
}
null tam, kde nesmí býtIllegalArgumentException nebo IllegalStateException
public class PaymentProcessor {
public PaymentResult charge(CreditCard card, double amount) {
// 1. Chyba programátora: fail-fast
if (card == null) {
throw new IllegalArgumentException("Card cannot be null");
}
if (amount <= 0) {
throw new IllegalArgumentException("Amount must be positive");
}
// ... komunikace s bankou ...
// 2. Očekávatelná doménová chyba: výsledek, nikoliv výjimka
if (bankResponse.isDeclined()) {
return PaymentResult.declined(bankResponse.getReason());
}
return PaymentResult.success(bankResponse.getTransactionId());
}
}