两个类共享相同、相似但不同方法的Java设计模式
假设我的应用程序实现了一些服务,如两个类共享相同、相似但不同方法的Java设计模式,java,oop,design-patterns,Java,Oop,Design Patterns,假设我的应用程序实现了一些服务,如ClassA和ClassB。两者既有相似之处,也有不同之处 这两个类都有一个start()方法,该方法具有相同的方法签名,但实现不同 这两个类都有一个具有不同签名和不同实现的process()方法 两个类都有相同的log()方法,即代码完全相同 甲级 B类 我很难想出一个“设计模式”,如何以更通用的方式组织它。从3日开始。我可以很容易地将此方法移动到一个超类,该超类可以扩展ClassA和ClassB。但是我如何设计应用程序,使1。二,。是否也考虑到了这一点 项目
ClassA
和ClassB
。两者既有相似之处,也有不同之处
start()
方法,该方法具有相同的方法签名,但实现不同process()
方法log()
方法,即代码完全相同ClassA
和ClassB
。但是我如何设计应用程序,使1。二,。是否也考虑到了这一点
项目1。听起来有点像我的接口,但我不知道如何将其与第3项的超类结合起来。那么第2项呢?我将设计它,以便
类A
和类B
扩展一个通用的抽象类,并为过程
方法的参数类型提供一个类型参数
公共抽象类基类{
公共抽象字符串开始(字符串s1、字符串s2);
公共抽象字符串进程(T值);
受保护的最终字符串日志(字符串s){
//共享日志实现
}
}
公共类A扩展了基类{
@凌驾
公共字符串开始(字符串s1、字符串s2){
//A.开始实施
}
@凌驾
公共字符串进程(字符串s){
//A.过程实施
}
}
公共类B扩展了基类{
@凌驾
公共字符串开始(字符串s1、字符串s2){
//B.开始实施
}
@凌驾
公共字符串进程(长l){
//B.过程实施
}
}
在Java 9+中,您可以通过给
log
一个默认实现,使用泛型公共接口基来代替抽象类。但是,这不允许您使实现类只能访问log
,也不阻止子类重写log
让另一个类实现日志,处理可以由实现服务接口的类完成:
interface Processable {
String start(String s1, String s2);
process(String s);
}
class LogDecorator {
private Processable p;
public LogDecorator(Processable p) {
this.p = p;
}
public String start(String s1, String s2) {
p.start(s1, s2);
}
public String process(String s) {
p.process();
}
protected final String log(String s) {
// logging
}
}
使用组合而不是继承如何?start
和process
的实现可以通过如下示例中的函数提供:
import java.util.function.BiFunction;
import java.util.function.Function;
class X<T> {
public String start(BiFunction<String, String, String> f, String s1, String s2) {
return f.apply(s1, s2);
}
public String process(Function<T, String> f, T t) {
return f.apply(t);
}
// example
public static void main(String[] args) {
X<String> xString = new X();
xString.start((s1, s2) -> s1 + s2, "a", "b");
X<Long> xLong = new X();
xLong.process((t) -> { Long tt = t * 2;return tt.toString(); }, 4L);
}
}
import java.util.function.BiFunction;
导入java.util.function.function;
X类{
公共字符串开始(双函数f、字符串s1、字符串s2){
返回f.apply(s1,s2);
}
公共字符串进程(函数f,T){
返回f.apply(t);
}
//范例
公共静态void main(字符串[]args){
X xString=new X();
xString.start((s1,s2)->s1+s2,“a”,“b”);
X xLong=新的X();
进程((t)->{longtt=t*2;返回tt.toString();},4L);
}
}
与前一个示例相同,但在构造函数中提供了实现,并使用功能接口而不是lambdas
import java.util.function.BiFunction;
import java.util.function.Function;
class StartFunctionExample implements BiFunction<String, String, String> {
@Override
public String apply(String s1, String s2) {
return s1 + s2;
}
}
class ProcessFunctionExample implements Function<Long, String> {
@Override
public String apply(Long t) {
Long tt = (t * 2);
return tt.toString();
}
}
class Z<T> {
private final BiFunction<String, String, String> startFunction;
private final Function<T, String> processFunction;
public Z(
BiFunction<String, String, String> startFunction,
Function<T, String> processFunction
) {
this.startFunction = startFunction;
this.processFunction = processFunction;
}
public String start(String s1, String s2) {
return startFunction.apply(s1, s2);
}
public String process(T t) {
return processFunction.apply(t);
}
// example
public static void main(String[] args) {
Z<Long> xLong = new Z(new StartFunctionExample(), new ProcessFunctionExample());
xLong.start("a", "b"); // ab
xLong.process(7L); // 14
}
}
import java.util.function.BiFunction;
导入java.util.function.function;
类StartFunctionExample实现了双功能{
@凌驾
公共字符串应用(字符串s1、字符串s2){
返回s1+s2;
}
}
类ProcessFunctionExample实现函数{
@凌驾
公共字符串应用(长t){
长tt=(t*2);
返回tt.toString();
}
}
Z类{
专用最终双功能启动功能;
私有最终函数processFunction;
公共Z(
双功能启动功能,
函数处理函数
) {
this.startFunction=startFunction;
this.processFunction=processFunction;
}
公共字符串开始(字符串s1、字符串s2){
返回startFunction.apply(s1,s2);
}
公共字符串进程(T){
返回processFunction.apply(t);
}
//范例
公共静态void main(字符串[]args){
Z xLong=new Z(new StartFunctionExample(),new ProcessFunctionExample());
xLong.start(“a”,“b”);//ab
xLong.进程(7L);//14
}
}
当然,您只能将常见行为提取到常见的超类中。将不同的东西提取到一个公共类中是没有意义的,不是吗?因此,当您的方法具有不同的签名和不同的实现时,它们不应该进入任何公共类。简而言之:提取两个类的共同点,并在具体实现中保留差异。可能oan会对具有不同参数的类似方法使用泛型。但这在很大程度上取决于这些方法的实际作用,所以这只是一个猜测。我怀疑这里的任何人都不能给你一个更具体的答案,因为你的问题很模糊。实现适配器。值得一问:你有没有想过让它们成为同一个类(比如一个start
重命名)?这些真的是不同的类型,必须在不同的类中吗?您没有提供足够的信息。如果不知道这些类将如何使用,就无法进行设计。当调用方调用例如start()
时,它是否希望在a和B之间使用统一的语义?剩下的方法呢?这解决了OP的问题,但继承是脆弱的。您将看到它是否适合未来的ClassC
,是否需要适应。很难预测未来,这就是继承意味着什么。
import java.util.function.BiFunction;
import java.util.function.Function;
class X<T> {
public String start(BiFunction<String, String, String> f, String s1, String s2) {
return f.apply(s1, s2);
}
public String process(Function<T, String> f, T t) {
return f.apply(t);
}
// example
public static void main(String[] args) {
X<String> xString = new X();
xString.start((s1, s2) -> s1 + s2, "a", "b");
X<Long> xLong = new X();
xLong.process((t) -> { Long tt = t * 2;return tt.toString(); }, 4L);
}
}
import java.util.function.BiFunction;
import java.util.function.Function;
class StartFunctionExample implements BiFunction<String, String, String> {
@Override
public String apply(String s1, String s2) {
return s1 + s2;
}
}
class ProcessFunctionExample implements Function<Long, String> {
@Override
public String apply(Long t) {
Long tt = (t * 2);
return tt.toString();
}
}
class Z<T> {
private final BiFunction<String, String, String> startFunction;
private final Function<T, String> processFunction;
public Z(
BiFunction<String, String, String> startFunction,
Function<T, String> processFunction
) {
this.startFunction = startFunction;
this.processFunction = processFunction;
}
public String start(String s1, String s2) {
return startFunction.apply(s1, s2);
}
public String process(T t) {
return processFunction.apply(t);
}
// example
public static void main(String[] args) {
Z<Long> xLong = new Z(new StartFunctionExample(), new ProcessFunctionExample());
xLong.start("a", "b"); // ab
xLong.process(7L); // 14
}
}