两个类共享相同、相似但不同方法的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()
    方法,即代码完全相同
  • 甲级 B类 我很难想出一个“设计模式”,如何以更通用的方式组织它。从3日开始。我可以很容易地将此方法移动到一个超类,该超类可以扩展
    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
        }
    }