Thank you for inviting
Let's start with something simple and rude. It is very simple to want to combine the two methods into one. In fact, when you are in one, the public parts are represented by the same thing. There are already brothers upstairs who have suggested using interfaces, which is OK, but the attributes are similar to the code structure. lambda+ generics
should be able to solve
.
We can see that there are only two
where the two methods need to be normalized.
-
customer.getDone ()
and client.getDone ()
-
customer.setLocation ("hongkong")
and client.setLocation ("hongkong")
The corresponding methods of
these two places should be Predicate
and Consumer
, respectively, so we can establish such a public method execute
.
public <T> void execute(T t, Predicate<T> donePredicate, Consumer<T> locationConsumer){
if(donePredicate.test(t)){
locationConsumer.accept(t);
}
System.out.println("result: "+ t);
}
so the previous two methods execute_customer
and execute_client
can be changed to
.
public void execute_customer(Customer customer){
this.execute(customer, Customer::getDone, c -> c.setLocation("hongkong"));
}
public void execute_client(Client client){
this.execute(client, Client::getDone, c -> c.setLocation("hongkong"));
}
but it is not recommended that you write this. After all, the method of three parameters is still very long. And Customer
and Client
may not have any business connection themselves, so forcibly integrating the code will only bring huge understanding costs to future maintenance, because they just happen to have two identical fields, and their processing patterns happen to be the same
.
but we can think about it another way. Since they happen to have two identical fields and their processing mode happens to be the same, and the subject also wants to combine them in the same method, then we don't look at Customer
and Client
, but just look at the attributes location
and isDone
. Can we just look at the processing of if
in the method to show whether their two attributes together represent a business? A service independent of Customer
and Client
has its own attributes location
and isDone
, as well as its own behavior, that is, the processing of if
. If we set such a service as Location
, it must be written as
.
public class Location {
private String location;
private Boolean isDone;
// get set toString ...
public void execute(){
if(this.getDone()){
this.setLocation("hongkong");
}
}
}
in this case, Customer
and Client
become
public class Customer {
private Location location;
}
public class Client {
private Location location;
}
so the method in Order
becomes
public void execute_customer(Customer customer){
customer.getLocation().execute();
}
public void execute_client(Client client){
client.getLocation().execute();
}
mm-hmm, to put it this way, the perfect yuppie, of course, everything is decided by the actual business. I just made some guesses based on the information provided by the current subject, and wrote a way that the actual business may need to be adjusted for reference only.
= small updates =
in the comments, the subject mentioned how to integrate with interfaces. In fact, this is also a small example of interface-oriented programming, ha. Interface-oriented programming means that the entire business logic needs to be assembled in a way predefined by the interface. The place where the interface is called, that is, the point of business abstraction
is actually about the same as the previous abstract point, or
-
customer.getDone ()
and client.getDone ()
-
customer.setLocation ("hongkong")
and client.setLocation ("hongkong")
these two points, previously expressed by functional interfaces, are represented by interfaces. For example, if we define such a functional interface, let's call it ILocation
, then it can be expressed in this way
.
public interface ILocation{
Boolean getDone();
void setLocation(String location);
}
It just so happens that the two methods are named
set
and
get
methods in
Client
and
Customer
, thus reducing the need to write implementation methods, and then
Client
and
Customer
can express in this way.
@Getter
@Setter
public class Client implements ILocation{
private String location;
private Boolean isDone;
}
@Getter
@Setter
public class Customer implements ILocation{
private String location;
private Boolean isDone;
}
because both the set
and get
method methods have been implemented ILocation
, after using the comments of lombok
, the code can add nothing (lombok's get
method for the default Boolean
type attribute is getIsDone
, so do not add is
beginning if necessary)
After
, you can write a common method in Order
.
public void execute(ILocation location){
if(location.getDone()){
location.setLocation("hongkong");
}
}
The implementation of
interface is roughly like this, which is for reference only.
= 2018-11-21 New question Update =
before answering the question, it is important to make it clear that any code integration, either within the scope of the business can be merged, or public structure or tool extraction, excessive forced integration of code, will only arbitrarily increase the coupling between businesses, bringing great stability to the subsequent expansion development
going back to the new problem of the subject, we can see that it is no longer simply solved by passing in parameters (although it is still possible, but it is not very friendly and not conducive to expansion). This time we can simply abstract such a business process from the direct two-segment method
public <T> List<T> retrieveEntityRecords(RequestParam request) {
List<String> ids = request.getId();
String location = request.getLocation();
boolean idsCk = CollectionUtils.isNotEmpty(ids) && ids.size() > 0;
boolean locationCk = !StringUtils.isEmpty(location);
List<T> result;
try {
if (idsCk) {
if (locationCk) {
// use [ids location] query db
} else {
// use [ids] query db
}
} else {
if (locationCk) {
// use [location] query db
} else {
// query all record in db
}
}
} catch (Exception e) {
throw new SystemException();
}
return result;
}
the above code should be the backbone code of the previous two methods, and it is also the core code of the business to be integrated this time. Let's take the common part away from the last question and deal with it, ah. Other specific implementation needs to be implemented with interfaces, and what needs to be implemented is that these four lines are annotated
.
// use [ids location] query db
// use [ids] query db
// use [location] query db
// query all record in db
so we define such an interface ILocationIdsQuery
(personal understanding is the common logic of querying according to Location and id, so it is so simply named), it defines four abstract methods
.
public interface ILocationIdsQuery<T> {
List<T> queryByIdsAndLocation(List<String> ids, String location);
List<T> queryByIds(List<String> ids);
List<T> queryLocation(String location);
List<T> query();
}
When
is defined in this way, you will find that this is consistent with the interface methods of customerRepository
and clientRepository
. If your customerRepository
and clientRepository
do not have a common parent interface, then you can add a parent interface to both of them ILocationIdsQueryExecutor
and supplement their implementation. If customerRepository
and clientRepository
have such a common parent interface,
once you have such a public interface, it's easy to open a utility class LocationIdsQueryUtils
(keep business consistency and make it easier for others to read the code, so it's just a name)
public class LocationIdsQueryUtils {
public static <T> List<T> doQuery(ILocationIdsQuery<T> locationIdsQuery, RequestParam request){
List<String> ids = request.getId();
String location = request.getLocation();
boolean idsCk = CollectionUtils.isNotEmpty(ids) && ids.size() > 0;
boolean locationCk = !StringUtils.isEmpty(location);
List<T> result;
try {
if (idsCk) {
if (locationCk) {
// use [ids location] query db
result = locationIdsQuery.queryByIdsAndLocation(ids, location);
} else {
// use [ids] query db
result = locationIdsQuery.queryByIds(ids);
}
} else {
if (locationCk) {
// use [location] query db
result = locationIdsQuery.queryByLocation(location);
} else {
// query all record in db
result = locationIdsQuery.queryAll();
}
}
} catch (Exception e) {
throw new SystemException();
}
return result;
}
}
now that you have such a tool class, the rest is much easier to write. You can call the tool class directly
.
public List<Customer> retrieveEntityRecords(RequestParam request) {
List<Customer> result = LocationIdsQueryUtils.doQuery(customerRepository, request);
return result;
}
public List<Client> retrieveEntityRecords(RequestParam request) {
List<Client> result = LocationIdsQueryUtils.doQuery(clientRepository, request);
return result;
}
this is roughly the case. For reference only, it will be paste
.
if you use classes, you can use reflect,
to optimize performance, you can use dome4j, to read xml configuration files, and
is similar to spring's ioc container to achieve a certain degree of performance optimization
simple demo forget to adopt
if you use interfaces, consider using decorator mode
public class Order
{
public void execute_object(String className){
try
{
if(className.equals("Customer")){
//className:
Class forName = Class.forName(className);
Customer customer=(Customer) forName.newInstance();
if(customer.getIsDone()){
customer.setLocation("hongkong");
}
System.out.println("result: "+ customer);
}
//className:
Class forName = Class.forName(className);
Client client=(Client) forName.newInstance();
if(client.getIsDone()){
client.setLocation("hongkong");
}
System.out.println("result: " + client);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
Order order = new Order();
order.execute_object("Customer");
}
}
is it better to use an interface?
there is no common part between your two objects, so it is not easy for you to use a common object to implement the extraction.