我正在继续开发 ASP.NET 应用程序(基于 Web 表单),其中以前的开发人员没有遵循良好的面向对象设计原则,即 SOLID(http://www.remondo.net/solid-principles-csharp-interface-隔离/)。我读过这样的帖子:长期存在的不正确的编程假设。
问题是很多类的内聚度低,耦合度高,而且很多类没有单一的职责(它们有很多)。我的具体问题是:我应该开始遵循 SOLID 原则还是只是通过 tweeking 继续开发并向类添加更多内容?过去我一直试图遵循像SOLID这样的原则,但是我所说的应用程序非常庞大和复杂。我是唯一从事该项目的开发人员。
完全重写目前是不可能的,但总有一天是可能的。
2012 年 7 月 15 日更新 到目前为止,我发现 SOLID 是一种设计原则,而 GRASP 是一种设计模式,它可能更适合 MVC 而不是页面控制器类型的应用程序。根据此链接,模拟对象也可能更适合 MVC:http : //www.asp.net/mvc/tutorials/older-versions/overview/asp-net-mvc-overview。根据迄今为止的响应,遵循 SOLID 原则始终是一种很好的做法。但是,到目前为止的答案并不推荐基于表单的应用程序的设计模式。
我开始学习 Node.js 并试图了解它与微框架 Express 相结合的架构。
我看到 Express 使用 Connect 作为中间件。Connect 使用一系列函数中的各种内容来扩充请求和响应对象,并且它提供了一个 API,因此您可以添加自定义中间件。我想这种扩充是一种在处理程序/控制器中保持简单和灵活的方法,而不是具有可变数量的参数和参数类型。下面是一个简单的 GET 处理程序示例:
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: 'Hello there!'});
})
Run Code Online (Sandbox Code Playgroud)
在 Node.js 专家的教程中,我看到了诸如使用 MongoDB 集合扩充请求对象之类的东西。在Azat Mardan的博客中,我看到了以下代码:
var db = mongoskin.db('mongodb://@localhost:27017/test', {safe:true})
app.param('collectionName', function(req, res, next, collectionName){
req.collection = db.collection(collectionName)
return next()
})
Run Code Online (Sandbox Code Playgroud)
上面的方法是使用路由名称中的“collectionName”参数作为控制请求扩充的条件。但是,我见过更丑陋的代码,其中数据库中间件附加在每个通过 Node.js 的请求上,而没有这种条件方法。
看看标准软件原则,如单一责任原则、关注点分离和可测试性,为什么用 MongoDB 集合对象和许多其他对象扩展请求是个好主意?是不是请求和响应对象以这种方式因功能而变得臃肿并且具有不可预测的状态和行为?这种模式从何而来,利弊和替代方案是什么?
据我所知,Factory Method比Simple Factory的主要优点之一是它不违反Open-Closed SOLID原则.也就是说,前者不需要在添加新类型时修改switch语句.
有一件我希望得到澄清.如果我要使用一个简单的工厂,我会有一个像这样的工厂(简化):
public class ObjectFactory {
public static IObject CreateObject(ObjectTypeEnum objectType) {
switch (objectType) {
case TypeA:
return ObjectA;
break;
case TypeB:
return ObjectB;
break;
case TypeC:
return ObjectC;
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
并且客户端会这样称呼它:
IObject myObject = ObjectFactory.CreateObject(objectType);
Run Code Online (Sandbox Code Playgroud)
文献中的缺点是在添加新对象类型时需要修改CreateObject.
但是使用Factory方法,我们不会将此修改从工厂移动到客户端,就像这样(客户端代码):
IObject myObject;
switch (objectType) {
case TypeA:
myObject = ObjectAFactory.CreateObject();
break;
case TypeB:
myObject = ObjectBFactory.CreateObject();
break;
case TypeC:
myObject = ObjectCFactory.CreateObject();
break;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,每次添加新类型时都需要修改客户端,而在之前的情况下需要修改工厂.那么一个优于另一个的优势是什么?请不要将此标记为重复,我已经查看了很多关于工厂的SO帖子,没有一个解决这个特定的区别.
是否有更好的解决方案不会违反客户或工厂方面的开放/封闭原则?
design-patterns factory factory-pattern open-closed-principle solid-principles
最近发现了依赖注入,我现在正试图掌握使用它的频率和距离。
例如,假设我有一个对话框,提示用户输入他们的注册详细信息——名字、姓氏、电话号码、序列号——诸如此类。应以各种方式验证数据(例如,名字和姓氏不为空,序列号为特定长度)。一旦通过验证,它应该被缓存在本地机器上,并发送到注册服务器。只有在所有这些事情都成功或用户取消后,该对话框才应关闭。
所以这可能是我们在这里尝试实现的四件事(职责):UI、验证、本地缓存、将数据发送到非本地服务器。
对话的职责是什么,应该注入什么?显然对话框是 UI,但是验证、缓存和数据发送都应该被注入吗?我认为他们这样做,否则对话框类必须知道数据字段背后的逻辑才能进行验证,它必须知道如何以及在何处缓存数据,以及如何将数据发送到某个地方。如果是这样,这可能会导致调用者端出现一些繁重的代码(假设我们通过构造函数进行注入,我认为这比 setter 函数更可取),例如
MyDialog dlg(new validator(), new cacher(), new sender());
Run Code Online (Sandbox Code Playgroud)
但也许这没问题?在多年看到诸如对话框之类的东西做所有事情的代码之后,它现在对我来说确实有点陌生。但我也可以看到这种情况如何迅速升级——如果还有其他各种各样的小事情需要做——有多少被注入的东西变得“太多”了?
请不要试图在示例场景中挑漏洞,我只是用它来说明。我对 DI 的原则更感兴趣,以及在什么时候你可能会走得太远。
我需要构建通知/警报系统的计划。
我有一个名为“Campaign”的对象,它有“Status”。状态可以是接受、拒绝、补充、工作等。我想在状态更改时发送通知/警报。
在我的门户中发送电子邮件通知和警报。
我不想在我操作 Campaign 的一个控制器中完成所有操作。所以我在考虑委托和活动。但最后我不知道该怎么做。
我在想什么:
领域模型:
class Campaign {
CampaignStatus Status { get; set;}
}
abstract class Notification {
// properties
}
class EmailNotification {
// properties specific for email
}
class Alert {
// properties specific for alerts
}
class CampaignAlert {
// properties specific for campaign alerts
}
Services:
INotificationsService {
Send();
}
IAlertsService : INotificationsService {
Get(); // I need showing list of alerts too
GetAll();
Update(); // for updating info if alert was viewed. …Run Code Online (Sandbox Code Playgroud) 我正在阅读为什么 Java 中的数组协变很糟糕(为什么数组协变而泛型是不变的?)。如果 aDog是 的子类型Animal,则 aDog[]是 的子类型Animal[]。这是一个问题,因为可以这样做:
Animal[] animals = new Dog[1];
animals[0] = new Cat();
Run Code Online (Sandbox Code Playgroud)
这与“正确”实现的泛型不同。AList<Dog>不是的子类型List<Animal>
我试图理解为什么它不好的本质,并且刚刚阅读了 LSP。它是否以任何方式违反了 LSP?似乎没有明显的违规行为。
generics language-design liskov-substitution-principle covariance solid-principles
该单一职责原则指出:
一个班级应该有一个,而且只有一个,改变的理由。
在打开/关闭原则指出:
您应该能够扩展类行为,而无需修改它。
如果一个类应该只有一个改变的理由,但不应该被修改,那么开发人员怎么能同时尊重这两个原则呢?
例子
工厂模式是一个很好的例子,它具有单一职责,但可能违反开放/封闭原则:
public abstract class Product
{
}
public class FooProduct : Product
{
}
public class BarProduct : Product
{
}
public class ProductFactory
{
public Product GetProduct(string type)
{
switch(type)
{
case "foo":
return new FooProduct();
case "bar":
return new BarProduct();
default:
throw new ArgumentException(...);
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我需要ZenProduct在后期添加到工厂时会发生什么?
oop single-responsibility-principle open-closed-principle solid-principles
我们的团队目前正在尝试一种 Angular 架构,我也想从其他人那里得到一些建议。
“基本” Angular 架构应该是这样的
组件有一个视图、它的逻辑和它的依赖关系。
但是我们想要做一种更可靠的方法,即“一个类、函数或方法应该只有一个职责”。所以我们认为我们可以让组件类只管理视图并将其逻辑导出到强链接服务。我们的架构现在看起来更像这样
但是使用强链接服务来导出组件的逻辑感觉有些奇怪,我们在团队中讨论过,Angular 服务的原则应该是执行业务逻辑,例如调用 API 并且应该在任何地方都可用,而不是强链接链接到类似组件的东西。
所以这就是我在这里的原因,我们希望从开发社区获得关于我们架构的建议,并确保我们不会朝着不稳定/错误的方向前进(请告诉我们您是否这么认为以及为什么)
这是我们所做的一个例子
我们有一个应该显示产品列表的组件。我们将逻辑导出到两个服务:
你可以想象这将很难在其他地方使用它,除非我们在另一个视图中需要相同的列表
我们使用了 SOLID 的控制反转,并使用 TokenInjection 注入了我们的服务,允许我们使用接口
该组件除了调用它的逻辑服务并处理视图(显示加载器,更改变量)之外什么都不做。给你代码
// IMPORTS ARE HERE
@Component({
selector: 'app-products-list',
templateUrl: './products-list.component.html',
styleUrls: ['./products-list.component.css'],
providers: [{
provide: BASE_PRODUCT_LIST_ITEM_SERVICE_TOKEN, // This is a token used to allows us to inject an interface
useClass: ProductListItemService,
},
{
provide: PRODUCTS_LIST_SERVICE_TOKEN, // This is a token used to allows us to inject an interface
useClass: …Run Code Online (Sandbox Code Playgroud) 我在我的项目中使用 UnitOfWork 和 Repository 模式。我正在尝试编码干净。
这是我的IUnitOfWork.cs (应用层)
public interface IUnitOfWork : IDisposable
{
int Save();
IGenericRepository<TEntity> Repository<TEntity>() where TEntity : class;
}
Run Code Online (Sandbox Code Playgroud)
UnitOfWork.cs的实现:(持久层)
public class UnitOfWork : IUnitOfWork
{
private readonly DBContext _context;
private Hashtable _repositories;
public UnitOfWork(DBContext context)
{
_context = context;
}
public IGenericRepository<T> Repository<T>() where T : class
{
if (_repositories == null)
_repositories = new Hashtable();
var type = typeof(T).Name;
if (!_repositories.ContainsKey(type))
{
var repositoryType = typeof(GenericRepository<>);
var repositoryInstance =
Activator.CreateInstance(repositoryType
.MakeGenericType(typeof(T)), _context);
_repositories.Add(type, …Run Code Online (Sandbox Code Playgroud) c# dependency-injection unit-of-work repository-pattern solid-principles
我目前是清洁代码和 SOLID 原则主题的新手。
我们已经UseCase为特定任务编写了一个。
using BusinessLogic.Classes.BusinessLogic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BusinessLogic.UseCases
{
public class DoASpecificTask<T> : Interfaces.IUseCase
where T : Interfaces.Connections.IQuery
{
T _Query;
Interfaces.Connections.IConnection<T> _Connection;
object _Parameters;
string _ServiceName;
Interfaces.ISendMessage _MessageSender;
public DoASpecificTask(T query, Interfaces.Connections.IConnection<T> connection, object parameters, string serviceName, Interfaces.ISendMessage messageSender)
{
_Query = query;
_Connection = connection;
_Parameters = parameters;
_ServiceName = serviceName;
_MessageSender = messageSender;
}
public void Execute()
{
Interfaces.Connections.IQueryResultList resultList = ExecuteReadDataOnConnection<T>.GetList(_Query, _Connection, _Parameters);
if …Run Code Online (Sandbox Code Playgroud) solid-principles ×10
c# ×3
angular ×1
asp.net ×1
asp.net-mvc ×1
connect ×1
covariance ×1
delegates ×1
events ×1
express ×1
factory ×1
generics ×1
javascript ×1
liskov-substitution-principle ×1
node.js ×1
oop ×1
single-responsibility-principle ×1
typescript ×1
unit-of-work ×1
vb.net ×1