标签: open-closed-principle

DAO模式和开放原则

我已经看过并使用过很多基于JDBC的旧代码,这些代码通常都是以CRUD方法开始的.我的问题特别涉及检索方法或"发现者".通常我发现DAO开始时有两种方法:

  • 找到并返回ALL
  • 基于唯一标识符检索特定实例

通常情况下,这两个发现者是不够的.我通常最终会看到一个DAO类被反复修改以添加如下所示的finder方法:

  • 找到并返回所有{condition}

当需要支持新的{conditions}或修改现有方法以添加新参数作为标志来修改方法内的SQL查询以支持其他条件时,会发生更多方法.

这是一种丑陋的方法,违反了开放封闭原则.每当需要支持一些新的检索条件时,看到DAO类不断修改,这一直是我的一个难得.对这个问题的研究经常指向Repository Pattern和封装条件,以便将其作为规范或查询对象进行检索,然后将它们传递给finder方法.但是,如果你有一个整个数据集的内存集合,或者你正在使用某种ORM(我正在使用旧的JDBC代码),这似乎是可行的.

我已经考虑过延迟加载整个数据集的解决方案,DAO作为内存中的集合进行管理,然后使用规范模式作为检索查询.然后我在集合上实现某种观察器,它只是在调用创建,更新或删除方法时更新数据库.但显然性能和可扩展性受到严重影响.

有什么想法吗?


感谢您到目前为止的回复.我有一个想法 - 您对使用命令/策略模式封装数据访问请求有何看法?每个单独的Concrete Command都可以表示特定类型的访问,并且可以传递给Invoker.我最终得到了许多具体的Command Command类,但是每一个都只关注一种访问,应该是非常可测试和隔离的.

    public abstract class Command<R>{
       public <R> execute();
       public void setArguments(CommandArguments args){
          //store arguments  
       }
    }

    //map based structure for storing and returning arguments
    public class CommandArguments{
         public String getAsString(String key);
         public String getAsInt(String key);
         //... others
    }

    //In some business class...
    Command command = CommandFactory.create("SearchByName");
    CommandArguments args = new CommandArguments();
    args.setValue("name", name);
    // others
    command.setArguments(args);
    List<Customer> list  = command.execute();
Run Code Online (Sandbox Code Playgroud)

java finder dao design-patterns open-closed-principle

10
推荐指数
1
解决办法
2051
查看次数

在java中扩展参数化工厂方法

我是OOP的新手并学习设计模式所以我写了一些简单的代码来试用一个Factory方法,一切看起来都不错,除非我想添加另一个子类型.这是迄今为止的代码:

public interface Person {
  public String getDescription();
}

public class Adult implements Person { 
  @Override
  public String getDescription() {
    return "I am an ADULT";
  }
}

public class Child implements Person {
  @Override
  public String getDescription() {
    return "I am a CHILD";
  }
}

public class PersonFactory {
  public Person create(int age) {
    if (age < 18) return new Child();
    return new Adult();
  }
}

public class ClientA {
  public static void main(String[] args) {
    PersonFactory personFactory = new …
Run Code Online (Sandbox Code Playgroud)

java factory-method open-closed-principle solid-principles

9
推荐指数
1
解决办法
467
查看次数

工厂方法模式是否违反开放/封闭原则?

请问工厂方法模式(不要与工厂或抽象工厂模式混淆)违反了开/关的原则

更新:为了澄清,我指的是具体类具有静态工厂方法的场景.例如(这是来自FMP上的维基百科页面):

class Complex 
{
    public static Complex fromCartesian(double real, double imag) {
        return new Complex(real, imag);
    }

    public static Complex fromPolar(double modulus, double angle) {
        return new Complex(modulus * cos(angle), modulus * sin(angle));
    }

    private Complex(double a, double b) {
       //...
    }
}
Run Code Online (Sandbox Code Playgroud)

私有构造函数不会阻止类被子类化,即扩展吗?

是否必须修改类以支持新的工厂方法?例如,如果该类最初只有来自Caresian,后来需要来自thePolar,那么是否必须修改该类才能支持此类?

这两个都不违反开放/封闭吗?

design-patterns factory-method open-closed-principle

8
推荐指数
2
解决办法
2668
查看次数

覆盖是否违反了开放/封闭原则?

开放/封闭原则规定一个类应该开放以进行扩展,但是关闭以进行修改.

我认为修改部分严格指的是改变基类的源代码.但我与某人说过,这也涉及从基类中重写方法.

这个解释对吗?

oop open-closed-principle solid-principles

8
推荐指数
2
解决办法
852
查看次数

OO设计,开放/封闭原则问题

我一直在思考这个面向对象的设计问题已经有一段时间了,并且无法提出一个令人满意的解决方案,所以我想在这里向群众展示一些意见.

我有一个游戏类代表一个基于回合制的棋盘游戏,我们可以假设它与此问题的目的类似于垄断.在我的设计中,我有一个包含TakeTurn方法的Player类.

游戏遍历所有球员 S和调用TakeTurn方法做一切必要的事情来完成转弯.我希望能够拥有n个玩家,并能够将其中的任意数量设置为计算机玩家.所以,我的想法是拥有一个HumanPlayer类和一个ComputerPlayer类,这两个类都派生自Player.

游戏者只知道播放器,并简单的调用TakeTurn每个方法球员轮流.我的问题在于,ComputerPlayer对象可以完全自动化,即保持Monopoly示例,可以决定使用某种逻辑购买属性.现在,使用HumanPlayer对象,它需要从实际用户获得一个输入,以便能够购买一个属性,这似乎意味着一个不同的接口,并可能意味着他们不应该派生

如果没有让Game类明确知道各种Player类的实际实现,我就无法找到解决问题的好方法.我总是可以在Game类中假设只有人类和计算机玩家并且有效地关闭它以进行扩展,但它似乎不是好的OO编程.

对此有任何意见将不胜感激.

language-agnostic oop ooad open-closed-principle

7
推荐指数
1
解决办法
895
查看次数

使用IoC和依赖注入,如何在不违反Open-Closed原则的情况下用新的实现层包装代码?

我试图弄清楚如何在实践中做到这一点,以免违反开放封闭原则.

假设我有一个名为HttpFileDownloader的类,它有一个函数,它接受一个url并下载一个文件,将html作为字符串返回.这个类实现了一个只有一个函数的IFileDownloader接口.所以在我的代码中我都引用了IFileDownloader接口,每当IFileDownloader被解析时,我的IoC容器都会返回一个HttpFileDownloader实例.

然后在一些使用之后,很明显有时服务器当时太忙并且抛出异常.我决定绕过这个,如果我得到异常,我将自动重试3次,并在每次重试之间等待5秒.

所以我创建了HttpFileDownloaderRetrier,它有一个函数在for循环中使用HttpFileDownloader,最多3个循环,每个循环之间等待5秒.因此,我可以测试HttpFileDownloadRetrier的"重试"和"等待"能力我通过让HttpFileDownloaderRetrier构造函数采用IFileDownloader来注入HttpFileDownloader依赖项.

所以现在我希望所有解析IFileDownloader都返回HttpFileDownloaderRetrier.但是,如果我这样做,那么HttpFileDownloadRetrier的IFileDownloader依赖将获得自己的实例,而不是HttpFileDownloader.

所以我可以看到我可以为HttpFileDownloader创建一个名为IFileDownloaderNoRetry的新接口,并更改HttpFileDownloader来实现它.但这意味着我正在改变违反Open Closed的HttpFileDownloader.

或者我可以为HttpFileDownloaderRetrier实现一个名为IFileDownloaderRetrier的新接口,然后更改所有其他代码以引用它而不是IFileDownloader.但是,我现在在所有其他代码中违反Open Closed.

那我在这里错过了什么?如何在不更改现有代码的情况下用新的实现层(重试和等待)包装现有实现(下载)?

如果有帮助,这里有一些代码:

public interface IFileDownloader
{
  string Download(string url);
}

public class HttpFileDownloader : IFileDownloader
{
  public string Download(string url)
  {
    //Cut for brevity - downloads file here returns as string
    return html;
  }
}

public class HttpFileDownloaderRetrier : IFileDownloader
{
  IFileDownloader fileDownloader;

  public HttpFileDownloaderRetrier(IFileDownloader fileDownloader)
  {
    this.fileDownloader = fileDownloader;
  }

  public string Download(string url)
  {
    Exception lastException = null;
    //try 3 shots of pulling a bad URL.  And wait 5 …
Run Code Online (Sandbox Code Playgroud)

c# dependency-injection ioc-container open-closed-principle

7
推荐指数
1
解决办法
1066
查看次数

抽象方法和开放原理

假设我有以下设计代码:

abstract class Root
{
  public abstract void PrintHierarchy();
}

class Level1 : Root
{
  override public void PrintHierarchy()
  {
    Console.WriteLine("Level1 is a child of Root");
  }
}

class Level2 : Level1
{
  override public void PrintHierarchy()
  {
    Console.WriteLine("Level2 is a child of Level1");
    base.PrintHierarchy();
  }
}
Run Code Online (Sandbox Code Playgroud)

如果我只是在看这个Level2类,我可以立即看到它Level2.PrintHierarchy遵循开放/封闭原则,因为它自己做了一些事情,它调用了它重写的基本方法.

但是,如果我只查看Level1该类,它似乎违反了OCP,因为它没有调用base.PrintHierarchy- 事实上,在C#中,编译器禁止它出现错误"无法调用抽象基础成员".

制作Level1似乎遵循OCP 的唯一方法是更改Root.PrintHierarchy为空虚拟方法,但之后我不再依赖编译器来强制实现派生类PrintHierarchy.

我在维护代码时遇到的真正问题是看到许多override不调用的方法base.Whatever().如果base.Whatever是抽象的,那么很好,但如果没有,那么该Whatever方法可能是被拉入接口而不是具体的可覆盖方法的候选者 - 或者类或方法需要以其他方式重构,但要么方式,它清楚地表明设计不佳.

如果没有记忆 …

c# oop open-closed-principle

7
推荐指数
1
解决办法
951
查看次数

超越开放原则

我有一个简单的程序,它根据用户提供的鼠标数据绘制几何图形.我有一个处理鼠标跟踪的类(它获取带有鼠标移动历史的List)和一个名为Shape的抽象类.从这个类中我可以得到一些额外的形状,比如Circle,Rectangle等 - 并且每个形状都会覆盖抽象的Draw()函数.

这一切都运行良好,但问题来自我希望用户能够手动切换所需的形状.我得到了鼠标数据,我知道应该绘制什么样的形状.问题是如何使代码"知道"它应该创建哪个对象并将适当的参数传递给构造函数.此时也不可能添加新的Shape衍生物,这是完全错误的.

我好像不想出来像这样的代码:

List<Shape> Shapes = new List<Shape>();
// somwhere later 

if(CurrentShape == "polyline"){
    Shapes.Add(new Polyline(Points)); 
}
else if (CurrentShape == "rectangle"){
    Shapes.Add(new Rectangle(BeginPoint, EndPoint));
}
// and so on.
Run Code Online (Sandbox Code Playgroud)

上面的代码清楚地证明了开放封闭原则.问题是我没有任何好主意如何克服它.主要问题是不同的Shapes具有不同参数的构造函数,这使得它更加麻烦.

我很确定这是一个常见的问题,但我不知道如何克服它.你有什么想法吗?

c# open-closed-principle

7
推荐指数
2
解决办法
761
查看次数

开放/封闭原则与依赖性倒置原则有什么区别?

DIP声明:

  • 高级模块不应该依赖于低级模块.两者都应该取决于抽象.
  • 抽象不应该依赖于细节.细节应取决于抽象.

OCP声明:

软件实体(类,模块,函数等)应该是可以扩展的,但是关闭以进行修改.

我认为如果我们满足DIP,它也会涵盖OCP,那么,为什么我们将这两个原则分开呢?

oop design-patterns open-closed-principle solid-principles dependency-inversion

6
推荐指数
3
解决办法
2049
查看次数

LARAVEL:如何使用SOLID原理的开闭原理?

我有以下结构可以使用开闭原理

class Payment{ 

    //this is not a model class
    // according to OC principle this class should not focus on the implementation

    private $paymentInterface;

    public function __construct(PaymentInterface $paymentInterface)
    {
        $this->paymentInterface = $paymentInterface;
    }


    //so store method does not know which implementation it will get
    public function store($request,$id)
    {
        return $this->paymentInterface->store($request,$id);
    }

}
Run Code Online (Sandbox Code Playgroud)

接口

interface PaymentInterface{
    public function store($request,$id = null);
}
Run Code Online (Sandbox Code Playgroud)

包含实现的支付服务类

class PaymentService implements PaymentInterface{
    public function store($request,$id = null){
        //payment store logic is here
    }
}
Run Code Online (Sandbox Code Playgroud)

控制者 …

php open-closed-principle solid-principles laravel

6
推荐指数
1
解决办法
291
查看次数