我已经看过并使用过很多基于JDBC的旧代码,这些代码通常都是以CRUD方法开始的.我的问题特别涉及检索方法或"发现者".通常我发现DAO开始时有两种方法:
通常情况下,这两个发现者是不够的.我通常最终会看到一个DAO类被反复修改以添加如下所示的finder方法:
当需要支持新的{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) 我是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) 请问工厂方法模式(不要与工厂或抽象工厂模式混淆)违反了开/关的原则?
更新:为了澄清,我指的是具体类具有静态工厂方法的场景.例如(这是来自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,那么是否必须修改该类才能支持此类?
这两个都不违反开放/封闭吗?
我一直在思考这个面向对象的设计问题已经有一段时间了,并且无法提出一个令人满意的解决方案,所以我想在这里向群众展示一些意见.
我有一个游戏类代表一个基于回合制的棋盘游戏,我们可以假设它与此问题的目的类似于垄断.在我的设计中,我有一个包含TakeTurn方法的Player类.
该游戏遍历所有球员 S和调用TakeTurn方法做一切必要的事情来完成转弯.我希望能够拥有n个玩家,并能够将其中的任意数量设置为计算机玩家.所以,我的想法是拥有一个HumanPlayer类和一个ComputerPlayer类,这两个类都派生自Player.
该游戏者只知道播放器,并简单的调用TakeTurn每个方法球员轮流.我的问题在于,ComputerPlayer对象可以完全自动化,即保持Monopoly示例,可以决定使用某种逻辑购买属性.现在,使用HumanPlayer对象,它需要从实际用户获得一个输入,以便能够购买一个属性,这似乎意味着一个不同的接口,并可能意味着他们不应该派生
如果没有让Game类明确知道各种Player类的实际实现,我就无法找到解决问题的好方法.我总是可以在Game类中假设只有人类和计算机玩家并且有效地关闭它以进行扩展,但它似乎不是好的OO编程.
对此有任何意见将不胜感激.
我试图弄清楚如何在实践中做到这一点,以免违反开放封闭原则.
假设我有一个名为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) 假设我有以下设计代码:
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方法可能是被拉入接口而不是具体的可覆盖方法的候选者 - 或者类或方法需要以其他方式重构,但要么方式,它清楚地表明设计不佳.
如果没有记忆 …
我有一个简单的程序,它根据用户提供的鼠标数据绘制几何图形.我有一个处理鼠标跟踪的类(它获取带有鼠标移动历史的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具有不同参数的构造函数,这使得它更加麻烦.
我很确定这是一个常见的问题,但我不知道如何克服它.你有什么想法吗?
DIP声明:
- 高级模块不应该依赖于低级模块.两者都应该取决于抽象.
- 抽象不应该依赖于细节.细节应取决于抽象.
OCP声明:
软件实体(类,模块,函数等)应该是可以扩展的,但是关闭以进行修改.
我认为如果我们满足DIP,它也会涵盖OCP,那么,为什么我们将这两个原则分开呢?
oop design-patterns open-closed-principle solid-principles dependency-inversion
我有以下结构可以使用开闭原理
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)
控制者 …