ins*_*ity 8 java oop polymorphism casting
我很抱歉这个长期的问题,但请耐心等待,我尽量让我的问题变得可以理解.如果你认为它可以更简洁随意编辑它.
我有一个客户端 - 服务器系统,客户端向服务器发送不同类型的请求,并根据请求获取响应.
客户端系统中的代码是:
int requestTypeA() {
Request request = new Request(TypeA);
Response response = request.execute();
// response for request of TypeA contains a int
return response.getIntResponse();
}
String requestTypeB() {
Request request = new Request(TypeB);
Response response = request.execute();
// response for request of TypeB contains a String
return response.getStringResponse();
}
Run Code Online (Sandbox Code Playgroud)
为了使上面的代码正确运行,Request该类是:
class Request {
Type type;
Request(Type type) {
this.type = type;
}
Response execute() {
if (type == TypeA) {
// do stuff
return new Response(someInt);
}
else if (type == TypeB) {
// do stuff
return new Response("someString");
}
else if ...
}
}
Run Code Online (Sandbox Code Playgroud)
并且Response是这样的:
class Response {
int someInt;
String someString;
Response(int someInt) {
this.someInt = someInt;
}
Response(String someString) {
this.someString = someString;
}
int getIntResponse() {
return someInt;
}
String getStringResponse() {
return someString;
}
}
Run Code Online (Sandbox Code Playgroud)
上述解决方案有两个问题:
execute方法将充满if,else if块.someString未初始化的响应,例如,它与A类请求的响应混淆.关于第一个问题,我提出的解决方案是使用多态.所以有一个父类,Request并且对于每种类型的请求都有一个子类Request,所以有一个RequestTypeA和RequestTypeB.所有类都覆盖了该execute方法.
关于2.问题我只有一个可能的想法如何解决它:类似于Request创建Response基于响应的子类并具有类似的东西.
interface Response {
}
class ResponseTypeA {
ResponseTypeA(int i) { ... }
int getIntResponse() { ... }
}
class ResponseTypeB {
ResponseTypeB(String s) { ... verify s is valid ... }
String getStringResponse() { ... }
}
Run Code Online (Sandbox Code Playgroud)
现在我可以肯定,如果类型的响应ResponseTypeB它将包含一个有效的字符串.我可以编写客户端代码如下:
String requestTypeB() {
Request request = new Request(TypeB);
ResponseTypeB response = (ResponseTypeB) request.execute();
return response.getStringResponse();
}
Run Code Online (Sandbox Code Playgroud)
现在我不得不输入强制转换类型execute.
我的主要问题是:在上述情况下,有没有办法避免类型转换?或者,如果您了解上述问题的更好解决方案(设计模式?)?
试图将请求与响应分开是徒劳的.它们由API绑定在一起 - R r = f(Q).
你有一个RequestA返回an int和a RequestB返回一个String.你可以清楚地做一些事情:
class Conversation<Q,R> {
R request (Q q, Class<R> rType) {
// Send the query (Q) and get a response R
}
}
class ConversationA extends Conversation<RequestA, Integer> {
}
class ConversationB extends Conversation<RequestB, String> {
}
Run Code Online (Sandbox Code Playgroud)
更加丰富的版本可能看起来像:
public class Test {
// Extend this to magically get a JSON-Like toString.
public static interface JSONObject {
public String asJSON();
}
class RequestA implements JSONObject {
@Override
public String asJSON() {
return "RequestA {}";
}
}
class RequestB implements JSONObject {
@Override
public String asJSON() {
return "RequestB {}";
}
}
static class Conversation<Q extends JSONObject, R> {
// Parser factory.
private static final JsonFactory factory = new JsonFactory();
// General query of the website. Takes an object of type Q and returns one of class R.
public R query(String urlBase, String op, Q q, Class<R> r) throws IOException {
// Prepare the post.
HttpPost postRequest = new HttpPost(urlBase + op);
// Get it all into a JSON string.
StringEntity input = new StringEntity(q.asJSON());
input.setContentType("application/json");
postRequest.setEntity(input);
// Post it and wait.
return requestResponse(postRequest, r);
}
private <R> R requestResponse(HttpRequestBase request, Class<R> r) throws IOException {
// Start a conversation.
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse response = httpclient.execute(request);
// Get the reply.
return readResponse(response, r);
}
private <R> R readResponse(CloseableHttpResponse response, Class<R> r) throws IOException {
// What was read.
R red = null;
try {
// What happened?
if (response.getStatusLine().getStatusCode() == 200) {
// Roll out the results
HttpEntity entity = response.getEntity();
if (entity != null) {
// Always make sure the content is closed.
try (InputStream content = entity.getContent()) {
red = parseAs(content, r);
}
}
} else {
// The finally below will clean up.
throw new IOException("HTTP Response: " + response.getStatusLine().getStatusCode());
}
} finally {
// Always close the response.
response.close();
}
return red;
}
private <R> R parseAs(InputStream content, Class<R> r) throws IOException {
JsonParser rsp;
// Roll it directly from the response stream.
rsp = factory.createJsonParser(content);
// Bring back the response.
return rsp.readValueAs(r);
}
}
static class ConversationA extends Conversation<RequestA, Integer> {
}
static class ConversationB extends Conversation<RequestB, String> {
}
public void test() throws IOException {
Integer a = new ConversationA().query("http://host/api", "JSON", new RequestA(), Integer.class);
String b = new ConversationB().query("http://host/api", "JSON", new RequestB(), String.class);
}
public static void main(String args[]) {
try {
new Test().test();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是源于JSON和Apache 的实际使用HttpClient- 但是,它可能无法发布,因为我已经删除了大多数错误处理和重试机制以简化.这里主要是为了证明建议机制的使用.
需要注意的是虽然在此代码中没有铸件(如要求的问题)有可能被铸造发生在幕后rsp.readValueAs(r),你不能得到解决JSON.
每个基于类型的开关(或 if/else if/else 链)都是糟糕的 OO 设计的标志。
正如 OldCurmudgeon 所说:每个请求都绑定到它的响应——一个请求和一个响应是一对。所以我会完全按照你在文本中的建议去做,但没有在你的代码中实现:
关于第一个问题,我想出的解决方案是使用多态性。所以有一个父类Request,对于每种类型的请求都有一个Request的子类,所以有一个RequestTypeA和RequestTypeB。所有的类都覆盖了 execute 方法。 所以基类看起来像:
/**
* Abstract class Request forms the base class for all your requests.
* Note that the implementation of execute() is missing.
*/
interface Request {
public Response execute();
}
/**
* Response-Interface just to have a common base class.
*/
interface Response {
}
Run Code Online (Sandbox Code Playgroud)
请注意,我将 Request 从具体类更改为接口。A 的具体实现(使用协变返回类型我避免了强制转换)看起来像:
/**
* Concrete request of type A.
*/
class RequestTypeA implements Request {
/** all fields typically for request A. */
private int i;
/**
* ctor, initializes all request fields.
*/
public RequestTypeA(int i) {
this.i = i;
}
/**
* Provide the exact response type. A feature Java 5 introduced is covariant return types, which permits an overriding method to return a more specialized type than the overriden method.
*/
public ResponseTypeA execute()
{
// Your implementation here
// you have to return a ResponseTypeA
}
}
class ResponseTypeA implements Response {
int getResponse() {
// Your implementation here
}
}
Run Code Online (Sandbox Code Playgroud)
B的具体实现:
/**
* Concrete request of type B.
*/
class RequestTypeB implements Request {
/** all fields typically for request B. */
private String s;
/**
* ctor, initializes all request fields.
*/
public RequestTypeB(String s) {
this.s = s;
}
/**
* Provide the exact response type. A feature Java 5 introduced is covariant return types, which permits an overriding method to return a more specialized type than the overriden method.
*/
public ResponseTypeB execute()
{
// Your implementation here
// you have to return a ResponseTypeB
}
}
class ResponseTypeB implements Response {
String getResponse() {
// Your implementation here
}
}
Run Code Online (Sandbox Code Playgroud)
这种设计确保:
用法示例:
RequestTypeA reqA = new RequestTypeA(5);
ResponseType resA = regA.execute();
int result = resA.getResponse();
Run Code Online (Sandbox Code Playgroud)
带有泛型的解决方案(由 OldCurmudgeon 提出)也很好。在以下情况下使用所有请求/响应对的手动实现而不是泛型:
查询Internet Chuck Norris 数据库的Groovy(类固醇上的 Java)中的玩具实现:
abstract class Request {
public abstract Response execute();
protected String fetch(String url) { new URL("http://api.icndb.com/jokes/$url").getText() }
}
interface Response {}
class RandomRequest extends Request {
public CommonResponse execute() {
new CommonResponse(result: fetch('random/'))
}
}
class SpecificRequest extends Request {
private int number;
public CommonResponse execute() {
new CommonResponse(result: fetch("$number"))
}
}
class CommonResponse implements Response {
private String result
String getJoke() {
def slurper = new groovy.json.JsonSlurper()
slurper.parseText(result).value.joke
}
}
println new RandomRequest().execute().joke
println new SpecificRequest(number: 21).execute().joke
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3484 次 |
| 最近记录: |